@elevasis/sdk 1.52.0 → 1.53.0
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.
- package/dist/{chunk-XC57JNMA.js → chunk-B2KAVPNB.js} +12 -6
- package/dist/{chunk-T6DTAP2U.js → chunk-FUOIYRIZ.js} +1 -1
- package/dist/{chunk-VYWGWJRW.js → chunk-HB7DC5LT.js} +18 -0
- package/dist/cli.cjs +97 -10
- package/dist/index.js +2 -2
- package/dist/node/index.js +1 -1
- package/dist/test-utils/index.js +3 -3
- package/dist/worker/index.js +3 -3
- package/package.json +3 -3
- package/reference/_navigation.md +3 -3
- package/reference/rules/content.md +4 -1
- package/reference/rules/deployment.md +12 -0
- package/reference/rules/frontend.md +2 -2
- package/reference/rules/organization-os.md +1 -1
- package/reference/rules/ui.md +18 -16
- package/reference/rules/vibe-intents.md +28 -6
- package/reference/rules/vibe.md +3 -2
- package/reference/scaffold/operations/propagation-pipeline.md +33 -19
- package/reference/scaffold/operations/scaffold-maintenance.md +1 -1
- package/reference/scaffold/recipes/customize-crm-actions.md +1 -1
- package/reference/scaffold/recipes/extend-content.md +2 -2
- package/reference/scaffold/recipes/extend-crm.md +4 -2
- package/reference/scaffold/recipes/extend-lead-gen.md +34 -5
- package/reference/scaffold/ui/customization.md +5 -5
- package/reference/scaffold/ui/recipes.md +11 -15
- package/reference/sdk/platform-tools/adapters-integration.mdx +2 -1
- package/reference/sdk/platform-tools/adapters-platform.mdx +1 -1
- package/reference/sdk/platform-tools/index.mdx +7 -7
- package/reference/sdk/resources/index.mdx +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __require } from './chunk-
|
|
1
|
+
import { __require } from './chunk-HB7DC5LT.js';
|
|
2
2
|
import { z, ZodError } from 'zod';
|
|
3
3
|
|
|
4
4
|
// src/define-contract.ts
|
|
@@ -7787,6 +7787,9 @@ function getLeadGenCrmHandoffResourceIds(model) {
|
|
|
7787
7787
|
(resource) => resource.systemPath === LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath && resource.ontology?.usesCatalogs?.includes(CRM_PIPELINE_CATALOG_ONTOLOGY_ID) === true
|
|
7788
7788
|
).map((resource) => resource.id);
|
|
7789
7789
|
}
|
|
7790
|
+
function isLeadGenCrmHandoffAdopted(model) {
|
|
7791
|
+
return getSystem(model, LEAD_GEN_API_INTERFACE.systemPath)?.apiInterface !== void 0 && getSystem(model, CRM_API_INTERFACE.systemPath)?.apiInterface !== void 0;
|
|
7792
|
+
}
|
|
7790
7793
|
function mergeLeadGenDerivedCatalogs(model) {
|
|
7791
7794
|
const baseCatalogTypes = model.ontology?.catalogTypes ?? {};
|
|
7792
7795
|
const derivedCatalogTypes = {};
|
|
@@ -7835,11 +7838,14 @@ registerBuiltInReadinessProfile(LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile,
|
|
|
7835
7838
|
registerReadinessInterfaceMarker(
|
|
7836
7839
|
LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath,
|
|
7837
7840
|
LEAD_GEN_CRM_HANDOFF_INTERFACE.interfaceKey,
|
|
7838
|
-
(model) =>
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7841
|
+
(model) => {
|
|
7842
|
+
if (!isLeadGenCrmHandoffAdopted(model)) return void 0;
|
|
7843
|
+
return {
|
|
7844
|
+
lifecycle: "active",
|
|
7845
|
+
readinessProfile: LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile,
|
|
7846
|
+
resourceIds: getLeadGenCrmHandoffResourceIds(model)
|
|
7847
|
+
};
|
|
7848
|
+
}
|
|
7843
7849
|
);
|
|
7844
7850
|
function findLeadGenTemplateStepCatalog(index) {
|
|
7845
7851
|
return Object.values(index.ontology.catalogTypes).find(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProcessingStageStatusSchema, ListBuilderStageKeySchema, zodToJsonSchema, LLMResponseParseError, errorToString, getErrorDetails, ExecutionError2, validateEntryPoint, validateTerminalSteps, validateStepReferences, WorkflowTimeoutError, WorkflowStalledError, WorkflowCancellationError, logWorkflowStart, detectCycle, WorkflowStepError, logStepStart, validateTerminalOutput, logStepSuccess, determineNextStep, logStepFailure, logExecutionPath, logWorkflowSuccess, logWorkflowFailure, estimateTokens, truncationCharBudget, buildIterationResponseSchema } from './chunk-
|
|
1
|
+
import { ProcessingStageStatusSchema, ListBuilderStageKeySchema, zodToJsonSchema, LLMResponseParseError, errorToString, getErrorDetails, ExecutionError2, validateEntryPoint, validateTerminalSteps, validateStepReferences, WorkflowTimeoutError, WorkflowStalledError, WorkflowCancellationError, logWorkflowStart, detectCycle, WorkflowStepError, logStepStart, validateTerminalOutput, logStepSuccess, determineNextStep, logStepFailure, logExecutionPath, logWorkflowSuccess, logWorkflowFailure, estimateTokens, truncationCharBudget, buildIterationResponseSchema } from './chunk-B2KAVPNB.js';
|
|
2
2
|
import { workerData, parentPort } from 'worker_threads';
|
|
3
3
|
import { z, ZodError } from 'zod';
|
|
4
4
|
import { createHmac } from 'crypto';
|
|
@@ -14,6 +14,22 @@ function toSdkResourceDescriptor(resource, getResourceOntologyBinding) {
|
|
|
14
14
|
systemId: resource.systemPath
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
function projectDisplayIdentity(resourceId, local, descriptor) {
|
|
18
|
+
if (descriptor.title !== void 0 && descriptor.title !== local.name) {
|
|
19
|
+
console.warn(
|
|
20
|
+
`[deployment-spec] "${resourceId}" name disagrees with its OM descriptor \u2014 using the OM title. config.name: "${local.name}", OM title: "${descriptor.title}"`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
if (descriptor.description !== void 0 && descriptor.description !== local.description) {
|
|
24
|
+
console.warn(
|
|
25
|
+
`[deployment-spec] "${resourceId}" description disagrees with its OM descriptor \u2014 using the OM description.`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: descriptor.title ?? local.name,
|
|
30
|
+
description: descriptor.description ?? local.description
|
|
31
|
+
};
|
|
32
|
+
}
|
|
17
33
|
function withPlatformResourceDescriptor(workflow, getWorkflowResourceDescriptor, getResourceOntologyBinding) {
|
|
18
34
|
const resource = getWorkflowResourceDescriptor(workflow.config.resourceId);
|
|
19
35
|
const sdkResource = toSdkResourceDescriptor(resource, getResourceOntologyBinding);
|
|
@@ -21,6 +37,7 @@ function withPlatformResourceDescriptor(workflow, getWorkflowResourceDescriptor,
|
|
|
21
37
|
...workflow,
|
|
22
38
|
config: {
|
|
23
39
|
...workflow.config,
|
|
40
|
+
...projectDisplayIdentity(sdkResource.id, workflow.config, sdkResource),
|
|
24
41
|
resource: sdkResource,
|
|
25
42
|
resourceId: sdkResource.id,
|
|
26
43
|
type: sdkResource.kind
|
|
@@ -39,6 +56,7 @@ function withPlatformAgentResourceDescriptor(agent, getAgentResourceDescriptor,
|
|
|
39
56
|
...agent,
|
|
40
57
|
config: {
|
|
41
58
|
...agent.config,
|
|
59
|
+
...projectDisplayIdentity(sdkResource.id, agent.config, sdkResource),
|
|
42
60
|
resource: sdkResource,
|
|
43
61
|
resourceId: sdkResource.id,
|
|
44
62
|
type: sdkResource.kind
|
package/dist/cli.cjs
CHANGED
|
@@ -46947,10 +46947,64 @@ var init_sse = __esm({
|
|
|
46947
46947
|
}
|
|
46948
46948
|
});
|
|
46949
46949
|
|
|
46950
|
+
// ../core/src/platform/api/describe-error.ts
|
|
46951
|
+
function parseAPIErrorEnvelope(body) {
|
|
46952
|
+
try {
|
|
46953
|
+
const parsed = JSON.parse(body);
|
|
46954
|
+
if (parsed && typeof parsed === "object" && typeof parsed.error === "string") {
|
|
46955
|
+
return parsed;
|
|
46956
|
+
}
|
|
46957
|
+
} catch {
|
|
46958
|
+
}
|
|
46959
|
+
return null;
|
|
46960
|
+
}
|
|
46961
|
+
function describeAPIError(status, envelope, options = {}) {
|
|
46962
|
+
const trailer = [];
|
|
46963
|
+
if (options.endpoint) trailer.push(` Endpoint: ${options.endpoint}`);
|
|
46964
|
+
if (envelope.requestId) trailer.push(` Request ID: ${envelope.requestId}`);
|
|
46965
|
+
if (envelope.fields) {
|
|
46966
|
+
for (const [field2, messages] of Object.entries(envelope.fields)) {
|
|
46967
|
+
trailer.push(` ${field2}: ${messages.join("; ")}`);
|
|
46968
|
+
}
|
|
46969
|
+
}
|
|
46970
|
+
const suffix = trailer.length > 0 ? `
|
|
46971
|
+
${trailer.join("\n")}` : "";
|
|
46972
|
+
if (status === 403) {
|
|
46973
|
+
return `403 Access denied: ${envelope.error}
|
|
46974
|
+
The API refused this deliberately -- the request reached the handler and was rejected,
|
|
46975
|
+
so nothing was written. Usual causes, in order of likelihood:
|
|
46976
|
+
- the role on this organization membership lacks the required permission
|
|
46977
|
+
- a row-level security policy refused the row
|
|
46978
|
+
- the credential is scoped to a different organization than the one addressed` + suffix;
|
|
46979
|
+
}
|
|
46980
|
+
if (status === 401) {
|
|
46981
|
+
return `401 Unauthorized: ${envelope.error}
|
|
46982
|
+
The credential was missing, malformed, or not accepted. This is authentication,
|
|
46983
|
+
not permission -- a valid credential that lacks access returns 403 instead.` + suffix;
|
|
46984
|
+
}
|
|
46985
|
+
if (status === 404) {
|
|
46986
|
+
return `404 Not found: ${envelope.error}
|
|
46987
|
+
Check the identifier. Deployed resources carry a suffix (e.g. '-workflow'), and a
|
|
46988
|
+
resource in another organization reads as absent rather than forbidden.` + suffix;
|
|
46989
|
+
}
|
|
46990
|
+
if (status === 429) {
|
|
46991
|
+
const retry = envelope.retryAfter ? ` Retry in ${envelope.retryAfter}s.` : "";
|
|
46992
|
+
return `429 Rate limited: ${envelope.error}${retry}${suffix}`;
|
|
46993
|
+
}
|
|
46994
|
+
const label = envelope.code ? `${status} ${envelope.code}` : String(status);
|
|
46995
|
+
return `API request failed (${label}): ${envelope.error}${suffix}`;
|
|
46996
|
+
}
|
|
46997
|
+
var init_describe_error = __esm({
|
|
46998
|
+
"../core/src/platform/api/describe-error.ts"() {
|
|
46999
|
+
"use strict";
|
|
47000
|
+
}
|
|
47001
|
+
});
|
|
47002
|
+
|
|
46950
47003
|
// ../core/src/platform/api/index.ts
|
|
46951
47004
|
var init_api2 = __esm({
|
|
46952
47005
|
"../core/src/platform/api/index.ts"() {
|
|
46953
47006
|
"use strict";
|
|
47007
|
+
init_describe_error();
|
|
46954
47008
|
}
|
|
46955
47009
|
});
|
|
46956
47010
|
|
|
@@ -48452,6 +48506,9 @@ function getLeadGenCrmHandoffResourceIds(model) {
|
|
|
48452
48506
|
(resource) => resource.systemPath === LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath && resource.ontology?.usesCatalogs?.includes(CRM_PIPELINE_CATALOG_ONTOLOGY_ID) === true
|
|
48453
48507
|
).map((resource) => resource.id);
|
|
48454
48508
|
}
|
|
48509
|
+
function isLeadGenCrmHandoffAdopted(model) {
|
|
48510
|
+
return getSystem(model, LEAD_GEN_API_INTERFACE.systemPath)?.apiInterface !== void 0 && getSystem(model, CRM_API_INTERFACE.systemPath)?.apiInterface !== void 0;
|
|
48511
|
+
}
|
|
48455
48512
|
function mergeLeadGenDerivedCatalogs(model) {
|
|
48456
48513
|
const baseCatalogTypes = model.ontology?.catalogTypes ?? {};
|
|
48457
48514
|
const derivedCatalogTypes = {};
|
|
@@ -48482,6 +48539,7 @@ var init_ontology_validation = __esm({
|
|
|
48482
48539
|
init_ontology();
|
|
48483
48540
|
init_systems();
|
|
48484
48541
|
init_migration_helpers();
|
|
48542
|
+
init_helpers();
|
|
48485
48543
|
init_engine();
|
|
48486
48544
|
LEAD_GEN_API_INTERFACE = SYSTEM_INTERFACE_PROFILES[0];
|
|
48487
48545
|
CRM_API_INTERFACE = SYSTEM_INTERFACE_PROFILES[1];
|
|
@@ -48563,11 +48621,14 @@ var init_ontology_validation = __esm({
|
|
|
48563
48621
|
registerReadinessInterfaceMarker(
|
|
48564
48622
|
LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath,
|
|
48565
48623
|
LEAD_GEN_CRM_HANDOFF_INTERFACE.interfaceKey,
|
|
48566
|
-
(model) =>
|
|
48567
|
-
|
|
48568
|
-
|
|
48569
|
-
|
|
48570
|
-
|
|
48624
|
+
(model) => {
|
|
48625
|
+
if (!isLeadGenCrmHandoffAdopted(model)) return void 0;
|
|
48626
|
+
return {
|
|
48627
|
+
lifecycle: "active",
|
|
48628
|
+
readinessProfile: LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile,
|
|
48629
|
+
resourceIds: getLeadGenCrmHandoffResourceIds(model)
|
|
48630
|
+
};
|
|
48631
|
+
}
|
|
48571
48632
|
);
|
|
48572
48633
|
}
|
|
48573
48634
|
});
|
|
@@ -49273,7 +49334,12 @@ async function request(method, endpoint, apiUrl, body) {
|
|
|
49273
49334
|
if (GATEWAY_STATUSES.has(response.status)) {
|
|
49274
49335
|
throw new Error(describeGatewayFailure(response.status, endpoint, elapsedMs));
|
|
49275
49336
|
}
|
|
49276
|
-
|
|
49337
|
+
const envelope = parseAPIErrorEnvelope(errorText);
|
|
49338
|
+
if (envelope) {
|
|
49339
|
+
throw new Error(describeAPIError(response.status, envelope, { endpoint }));
|
|
49340
|
+
}
|
|
49341
|
+
throw new Error(`API request failed (${response.status}): ${errorText}
|
|
49342
|
+
Endpoint: ${endpoint}`);
|
|
49277
49343
|
}
|
|
49278
49344
|
if (response.status === 204) {
|
|
49279
49345
|
return {};
|
|
@@ -49296,6 +49362,7 @@ var DEFAULT_TIMEOUT_MS, GATEWAY_STATUSES;
|
|
|
49296
49362
|
var init_api_client = __esm({
|
|
49297
49363
|
"src/cli/api-client.ts"() {
|
|
49298
49364
|
"use strict";
|
|
49365
|
+
init_src();
|
|
49299
49366
|
init_config2();
|
|
49300
49367
|
init_readiness_failure();
|
|
49301
49368
|
DEFAULT_TIMEOUT_MS = 2 * 60 * 60 * 1e3;
|
|
@@ -49308,7 +49375,7 @@ function wrapAction(commandName, fn) {
|
|
|
49308
49375
|
return async (...args) => {
|
|
49309
49376
|
try {
|
|
49310
49377
|
await fn(...args);
|
|
49311
|
-
process.exitCode
|
|
49378
|
+
process.exitCode ??= 0;
|
|
49312
49379
|
} catch (error46) {
|
|
49313
49380
|
const errorMessage = error46 instanceof Error ? error46.message : String(error46);
|
|
49314
49381
|
console.error(source_default.red("\nError:"), errorMessage);
|
|
@@ -49330,7 +49397,7 @@ var init_package = __esm({
|
|
|
49330
49397
|
"package.json"() {
|
|
49331
49398
|
package_default = {
|
|
49332
49399
|
name: "@elevasis/sdk",
|
|
49333
|
-
version: "1.
|
|
49400
|
+
version: "1.53.0",
|
|
49334
49401
|
description: "SDK for building Elevasis organization resources",
|
|
49335
49402
|
type: "module",
|
|
49336
49403
|
bin: {
|
|
@@ -58735,6 +58802,13 @@ function mergeOmDoctorDiagnostics(report, extra, options = {}) {
|
|
|
58735
58802
|
const summary = summarize(merged);
|
|
58736
58803
|
return { ...report, ok: summary.error === 0, summary, diagnostics: merged };
|
|
58737
58804
|
}
|
|
58805
|
+
function requireDeployedUnavailableDiagnostic(unavailableReason) {
|
|
58806
|
+
return {
|
|
58807
|
+
severity: "error",
|
|
58808
|
+
code: "deployed-readiness-unavailable",
|
|
58809
|
+
message: `--require-deployed was set but the deployed-snapshot readiness check did not run: ${unavailableReason}`
|
|
58810
|
+
};
|
|
58811
|
+
}
|
|
58738
58812
|
function formatDiagnostic(diagnostic) {
|
|
58739
58813
|
const target = diagnostic.targetId ? ` (${diagnostic.targetId})` : "";
|
|
58740
58814
|
const source = diagnostic.source ? ` [${diagnostic.source}]` : "";
|
|
@@ -58769,9 +58843,15 @@ function formatOmDoctorReport(report) {
|
|
|
58769
58843
|
// src/cli/commands/om/doctor.ts
|
|
58770
58844
|
function registerOmDoctorCommand(program3) {
|
|
58771
58845
|
program3.command("om:doctor").description(
|
|
58772
|
-
"Reduced model doctor \u2014 runs 3 of the platform's 5 checks, plus deployed readiness\n Checks: ontology references, knowledge links, rename-orphan hints\n NOT run (monorepo-only): UI-manifest consistency, contract-ref resolution\n Readiness is read from the deployed snapshot; it reports NOT RUN when offline\n Example: elevasis-sdk om:doctor\n Example: elevasis-sdk om:doctor --scope sales.crm\n Example: elevasis-sdk om:doctor --skip-deployed\n Example: elevasis-sdk om:doctor --json"
|
|
58773
|
-
).option("--json", "Output as grouped JSON envelope").option("--scope <systemPath>", "Limit diagnostics to a system path and descendants").option("--skip-deployed", "Structural checks only \u2014 do not ask the API about readiness").option(
|
|
58846
|
+
"Reduced model doctor \u2014 runs 3 of the platform's 5 checks, plus deployed readiness\n Checks: ontology references, knowledge links, rename-orphan hints\n NOT run (monorepo-only): UI-manifest consistency, contract-ref resolution\n Readiness is read from the deployed snapshot; it reports NOT RUN when offline\n Example: elevasis-sdk om:doctor\n Example: elevasis-sdk om:doctor --scope sales.crm\n Example: elevasis-sdk om:doctor --skip-deployed\n Example: elevasis-sdk om:doctor --require-deployed\n Example: elevasis-sdk om:doctor --json"
|
|
58847
|
+
).option("--json", "Output as grouped JSON envelope").option("--scope <systemPath>", "Limit diagnostics to a system path and descendants").option("--skip-deployed", "Structural checks only \u2014 do not ask the API about readiness").option(
|
|
58848
|
+
"--require-deployed",
|
|
58849
|
+
"Fail (non-zero exit) if the deployed-snapshot readiness check is unavailable \u2014 API unreachable or no platform key \u2014 instead of the default degraded pass. Opt-in: default behavior is unchanged, and this is rejected together with --skip-deployed."
|
|
58850
|
+
).option("--prod", "Target production (overrides NODE_ENV=development)").option("--api-url <url>", "API URL").action(
|
|
58774
58851
|
wrapAction("om:doctor", async (options) => {
|
|
58852
|
+
if (options.requireDeployed && options.skipDeployed) {
|
|
58853
|
+
throw new Error("--require-deployed and --skip-deployed are mutually exclusive");
|
|
58854
|
+
}
|
|
58775
58855
|
let report;
|
|
58776
58856
|
try {
|
|
58777
58857
|
const projectRoot = getProjectRoot();
|
|
@@ -58786,6 +58866,13 @@ function registerOmDoctorCommand(program3) {
|
|
|
58786
58866
|
});
|
|
58787
58867
|
if (readiness.unavailableReason !== void 0) {
|
|
58788
58868
|
report.sources.readinessUnavailableReason = readiness.unavailableReason;
|
|
58869
|
+
if (options.requireDeployed) {
|
|
58870
|
+
report = mergeOmDoctorDiagnostics(
|
|
58871
|
+
report,
|
|
58872
|
+
[requireDeployedUnavailableDiagnostic(readiness.unavailableReason)],
|
|
58873
|
+
{ scope: options.scope }
|
|
58874
|
+
);
|
|
58875
|
+
}
|
|
58789
58876
|
} else {
|
|
58790
58877
|
report.sources.readiness = {
|
|
58791
58878
|
activeDeploymentId: readiness.activeDeploymentId,
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ProspectingBuildTemplateSchema as BuildTemplateSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, bindResourceDescriptor, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineStep, defineTopology, defineTopologyRelationship, defineWorkflow, defineWorkflowConfig, deriveActions, diagnosticOutput, integrationInput, isBuiltInReadinessProfile, isZodType, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, validateDeclaredSystemInterfaceReadiness, validateResourceGovernance } from './chunk-
|
|
2
|
-
export { projectDeploymentSpec, projectTopologyRelationships, toSdkResourceDescriptor, withPlatformAgentResourceDescriptor, withPlatformAgentResourceDescriptors, withPlatformIntegrationResourceDescriptor, withPlatformIntegrationResourceDescriptors, withPlatformResourceDescriptor, withPlatformResourceDescriptors } from './chunk-
|
|
1
|
+
export { ActivityEventSchema, BuildPlanSnapshotStepSchema, ProspectingBuildTemplateSchema as BuildTemplateSchema, ContractRefResolutionError, CrmStageKeySchema, CrmStateKeySchema, EmailSchema, ExecutionError, ListBuilderStageKeySchema, ProcessingStageStatusSchema, RegistryValidationError, ResourceRegistry, StepType, ToolingError, bindResourceDescriptor, compileBusinessOntologyValidationIndex, concurrentPool, createLeadGenStageValidators, defineContract, defineResource, defineResourceOntology, defineResources, defineStep, defineTopology, defineTopologyRelationship, defineWorkflow, defineWorkflowConfig, deriveActions, diagnosticOutput, integrationInput, isBuiltInReadinessProfile, isZodType, lookupReadinessProfile, parseTopologyNodeRef, registerReadinessProfile, resolveContractRef, runDiagnostic, splitName, topologyRef, topologyRelationship, validateDeclaredSystemInterfaceReadiness, validateResourceGovernance } from './chunk-B2KAVPNB.js';
|
|
2
|
+
export { projectDeploymentSpec, projectTopologyRelationships, toSdkResourceDescriptor, withPlatformAgentResourceDescriptor, withPlatformAgentResourceDescriptors, withPlatformIntegrationResourceDescriptor, withPlatformIntegrationResourceDescriptors, withPlatformResourceDescriptor, withPlatformResourceDescriptors } from './chunk-HB7DC5LT.js';
|
package/dist/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { projectDeploymentSpec, projectTopologyRelationships, toSdkResourceDescriptor, withPlatformAgentResourceDescriptor, withPlatformAgentResourceDescriptors, withPlatformIntegrationResourceDescriptor, withPlatformIntegrationResourceDescriptors, withPlatformResourceDescriptor, withPlatformResourceDescriptors } from '../chunk-
|
|
1
|
+
export { projectDeploymentSpec, projectTopologyRelationships, toSdkResourceDescriptor, withPlatformAgentResourceDescriptor, withPlatformAgentResourceDescriptors, withPlatformIntegrationResourceDescriptor, withPlatformIntegrationResourceDescriptors, withPlatformResourceDescriptor, withPlatformResourceDescriptors } from '../chunk-HB7DC5LT.js';
|
|
2
2
|
import { readFileSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
3
3
|
import { relative, dirname, resolve, join, extname } from 'path';
|
|
4
4
|
import { compile } from '@mdx-js/mdx';
|
package/dist/test-utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { executeWorkflow } from '../chunk-
|
|
2
|
-
import { validateDeploymentSpec, validateRelationships } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
1
|
+
import { executeWorkflow } from '../chunk-FUOIYRIZ.js';
|
|
2
|
+
import { validateDeploymentSpec, validateRelationships } from '../chunk-B2KAVPNB.js';
|
|
3
|
+
import '../chunk-HB7DC5LT.js';
|
|
4
4
|
import { vi } from 'vitest';
|
|
5
5
|
|
|
6
6
|
// src/test-utils/workflow.ts
|
package/dist/worker/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ListBuilderResultSchema, ListBuilderResultsSchema, PlatformToolError, acqDb, approval, artifacts, classifyPlatformToolError, content, createAdapter, createAnymailfinderAdapter, createApifyAdapter, createAttioAdapter, createCaptionGenerationWorkflow, createCaptureInstagramMetricsWorkflow, createClickUpAdapter, createDropboxAdapter, createGmailAdapter, createGoogleSheetsAdapter, createImageAnalysisWorkflow, createInstagramAdapter, createInstantlyAdapter, createMillionVerifierAdapter, createPublishInstagramWorkflow, createResendAdapter, createSignatureApiAdapter, createStripeAdapter, createTombaAdapter, crm, email, executeWorkflow, execution, generateHmacToken, list, listBuilderWorkflow, llm, notifications, pdf, platform, projects, scheduler, startWorker, storage, toContentMetrics } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
1
|
+
export { ListBuilderResultSchema, ListBuilderResultsSchema, PlatformToolError, acqDb, approval, artifacts, classifyPlatformToolError, content, createAdapter, createAnymailfinderAdapter, createApifyAdapter, createAttioAdapter, createCaptionGenerationWorkflow, createCaptureInstagramMetricsWorkflow, createClickUpAdapter, createDropboxAdapter, createGmailAdapter, createGoogleSheetsAdapter, createImageAnalysisWorkflow, createInstagramAdapter, createInstantlyAdapter, createMillionVerifierAdapter, createPublishInstagramWorkflow, createResendAdapter, createSignatureApiAdapter, createStripeAdapter, createTombaAdapter, crm, email, executeWorkflow, execution, generateHmacToken, list, listBuilderWorkflow, llm, notifications, pdf, platform, projects, scheduler, startWorker, storage, toContentMetrics } from '../chunk-FUOIYRIZ.js';
|
|
2
|
+
import '../chunk-B2KAVPNB.js';
|
|
3
|
+
import '../chunk-HB7DC5LT.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.53.0",
|
|
4
4
|
"description": "SDK for building Elevasis organization resources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"vitest": "^3.2.4",
|
|
65
65
|
"zod": "^4.1.0",
|
|
66
66
|
"@repo/core": "0.69.0",
|
|
67
|
-
"@repo/
|
|
68
|
-
"@repo/
|
|
67
|
+
"@repo/eslint-config": "0.0.0",
|
|
68
|
+
"@repo/typescript-config": "0.0.0"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
71
71
|
"lint": "eslint src --max-warnings 0",
|
package/reference/_navigation.md
CHANGED
|
@@ -295,9 +295,9 @@ Docs-site pages indexed: 38.
|
|
|
295
295
|
| Getting Started | `sdk/getting-started.mdx` | Set up your Elevasis SDK project and run your first deployment |
|
|
296
296
|
| Human-in-the-Loop (HITL) Workflows | `sdk/human-in-the-loop.mdx` | How a workflow step opens an approval task, how it reaches the command queue, and how selecting an action resumes work -- the story that connects the approval adapter, checkpoint metadata, and the queue CLI. |
|
|
297
297
|
| @elevasis/sdk | `sdk/index.mdx` | Build and deploy workflows, agents, and resources with the Elevasis SDK |
|
|
298
|
-
| Integration Adapters | `sdk/platform-tools/adapters-integration.mdx` | Auto-generated table of all
|
|
299
|
-
| Platform Adapters | `sdk/platform-tools/adapters-platform.mdx` | Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker
|
|
300
|
-
| Platform Tools | `sdk/platform-tools/index.mdx` | Access
|
|
298
|
+
| Integration Adapters | `sdk/platform-tools/adapters-integration.mdx` | Auto-generated table of all 14 integration (credential-bound) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the INTEGRATION_EXPORTS list in the generator, checked against the adapter directory on every run. |
|
|
299
|
+
| Platform Adapters | `sdk/platform-tools/adapters-platform.mdx` | Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the PLATFORM_EXPORTS list in the generator, checked against the adapter directory on every run. |
|
|
300
|
+
| Platform Tools | `sdk/platform-tools/index.mdx` | Access 28 adapters (14 integration + 14 platform) from your SDK workflows -- typed adapters, credential security model, and working code examples |
|
|
301
301
|
| Adapter Type Safety | `sdk/platform-tools/type-safety.mdx` | SDK worker adapter type safety patterns - required fields, discriminated unions, and intentionally loose types |
|
|
302
302
|
| The Deployment Spec Pattern | `sdk/project-deployment-spec.mdx` | How projectDeploymentSpec and defineWorkflowConfig assemble the DeploymentSpec a scaffolded project actually ships, using operations/src/index.ts as the reference. |
|
|
303
303
|
| Writing Resources | `sdk/resources/index.mdx` | Guide to creating descriptor-backed workflows and agents with the Elevasis SDK |
|
|
@@ -10,11 +10,14 @@ paths:
|
|
|
10
10
|
|
|
11
11
|
# Content
|
|
12
12
|
|
|
13
|
-
- **These routes render and do nothing until the System behind them is
|
|
13
|
+
- **These routes render and do nothing until the System behind them is adopted.** `content` **does** have an entry in `core/config/organization-model/systems.ts`, alongside CRM and lead-gen. Do not add a second one. The entry ships `enabled: true` with `lifecycle: 'draft'`, and that draft state is the deliberate opt-out, not a half-finished System: with no `apiInterface`, the shared Content pages have no API surface to call. Adoption means flipping `lifecycle` to `'active'` and adding an `apiInterface` once this project has real content workflows -- `defineContentSystem` throws on empty `resources`, which is exactly why the template does not call it.
|
|
14
14
|
- **One recipe covers this surface and no other rule names it.** `extend-content.md` covers the System, its pipeline/step/status/pillar/platform catalogs, and the `content` workflow adapter. Read it before authoring.
|
|
15
15
|
- **A pipeline is data, not code.** Pipelines and their ordered steps are catalog records (`content:catalog/pipeline`, `content:catalog/{pipelineId}-steps`); adding one is an org-model edit plus one workflow per step, never a shared-UI or route change.
|
|
16
16
|
- **Pipeline, step, status, and pillar vocabulary is model-owned, never a local constant.** Copying catalog entries into a `const` is architecturally excluded -- every project owns its own model, so the copy rots silently. Read catalog entries from the resolved model.
|
|
17
17
|
- **`apiInterface` is adopt-only here.** Content uses the flat `system.apiInterface` marker on the `content` System path; readiness is derived from scoped resources, ontology bindings, and required catalogs -- never invent a readiness profile.
|
|
18
|
+
- **Every step records an attempt when it advances -- human steps included.** `content_items.processing_state` is read-only and rebuilt from that item's attempts on every attempt write; there is no `updateProcessingState` anywhere in the stack, so **writing an attempt is the only way to move an item**. An agent or workflow step satisfies this for free, because the execution behind it writes `running` and patches the terminal status. A **human** step has no execution and therefore no producer, so the surface that advances it is the only thing that can write its attempt. A panel that moves the operator on with a bare client-side stepper call records nothing: the step never reaches `'success'`, and board placement pins the item to that column however far it actually goes. Nothing enforces this -- no gate, no type -- which is why it is stated here. It reached two tenants at once purely because the rule lived in the board-derivation implementation and nowhere a panel author would look.
|
|
19
|
+
- **Two shapes satisfy that contract.** **Inline** -- the step writes its own attempt as it advances; available to any human step reached with an item in hand, and the only shape most projects need. **Backfilled at creation** -- a pipeline that deliberately defers the first write (so an abandoned selection leaves no rows behind) runs its first human steps with no item to write against, so those attempts go in one pass right after the item is created, derived from wherever creation lands rather than listed per pipeline. Both write `payload: {}` and `sourceExecutionId: null` -- a person doing the step is the result, and there is no execution to name. Guard the write on an existing `'success'` entry so walking back and forward does not pile up rows, and never let a failed write block the operator: the step's work is genuinely done, and the next walk through repairs the projection.
|
|
20
|
+
- **A review is an attempt too.** A human clearing a gate writes an attempt on the step being cleared, via `content_items/:id/review` -- which resolves the exact step through the open-review-gate query rather than guessing. Do not widen `content_items` with per-gate columns. A review attempt legitimately has `sourceExecutionId: null` (a judgment call has no execution) and carries the reviewer's identity in `createdBy`. That route is only reachable for a step an execution actually produced: `getOpenContentReviewGates` resolves gates through `executionId`, so a human-actor step with no `action` and no `resource` structurally can never have an open gate to clear. For those steps the inline attempt above is not the preferred shape, it is the only one.
|
|
18
21
|
|
|
19
22
|
## Related Rules
|
|
20
23
|
|
|
@@ -56,6 +56,18 @@ Deploy accepts `--major`, `--minor`, `--patch` flags to bump the deployment vers
|
|
|
56
56
|
1. **Bundle:** esbuild compiles `operations/src/index.ts` + all dependencies into a single self-contained CJS file. No `node_modules` needed at runtime.
|
|
57
57
|
2. **Metadata:** Resource definitions, OM Resources descriptor bindings, Zod schemas (converted to JSON Schema), relationships, triggers.
|
|
58
58
|
|
|
59
|
+
## The OM Descriptor Owns Display Identity
|
|
60
|
+
|
|
61
|
+
A resource's `name` and `description` in its `operations/src/**` config are **not** what the platform shows. At deploy time the projected spec takes `title` and `description` from that resource's OM descriptor in `core/config/organization-model.ts` and overrides the locally declared strings, because the descriptor is what Command Center's action surfaces render and a config string only ever reached the execution log.
|
|
62
|
+
|
|
63
|
+
Deploy warns per resource when the two disagree:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
[deployment-spec] "<resource-id>" name disagrees with its OM descriptor -- using the OM title.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That warning does not fail the deploy. Fix it by editing the OM descriptor when the descriptor is wrong, or the config when the config is. Editing only the config and redeploying changes nothing a user sees.
|
|
70
|
+
|
|
59
71
|
## Environment
|
|
60
72
|
|
|
61
73
|
- `ELEVASIS_PLATFORM_KEY` in `.env` is required for CLI auth (used for every deploy unless `NODE_ENV=development` with no `--prod`)
|
|
@@ -16,7 +16,7 @@ paths:
|
|
|
16
16
|
- `routeTree.gen.ts` is auto-generated on `pnpm dev` -- never edit manually
|
|
17
17
|
- Auth protection: wrap page content with `ProtectedRoute` from `@elevasis/ui/features/auth`. Gate further with `AccessGuard accessKey={...}` nested inside `ProtectedRoute` -- a System path for system gating, or an `AccessKeys` constant (e.g. `AccessKeys.platformAdmin`) for permission-backed gating. `FeatureGuard`, `SystemGuard`, `SurfaceGuard`, and `AdminGuard` are retired -- do not reintroduce them
|
|
18
18
|
- **For a System's top-level route, use `ProtectedSystemRoute accessKey={...}` from `@elevasis/ui/features/auth` instead of writing that pairing by hand.** It expands to exactly the `ProtectedRoute` + `AccessGuard` nesting above and adds `SystemUnavailableState` as the guard's `fallback`, so a denied user sees the reason rather than `AccessGuard`'s blank `fallback = null` default. Every System route in the template ships this shape; see `ui.md` "System route guarding". Keep `createFileRoute` in the route file and keep bare `AccessGuard` for gating below the route level
|
|
19
|
-
- **Two `ProtectedRoute` components exist and the subpath you import from decides what the user sees while the app initializes.** `@elevasis/ui/features/auth` is the one route files want: it wraps the base guard with an animated full-screen loader and a default `
|
|
19
|
+
- **Two `ProtectedRoute` components exist and the subpath you import from decides what the user sees while the app initializes.** `@elevasis/ui/features/auth` is the one route files want: it wraps the base guard with an animated full-screen loader and a default `ServiceUnavailableScreen` error fallback, which classifies the initialization failure and retries on a backoff. `@elevasis/ui/auth` exports the headless base guard, whose `fallback` defaults to `null` -- importing it without passing a `fallback` renders a blank screen for the whole initialization window and swallows initialization errors. Reach for the headless one only when the surface renders its own loading state. `AccessKeys` is a plain constant table and stays on `@elevasis/ui/auth` (or `@elevasis/ui/hooks`) either way
|
|
20
20
|
- Never fork `@elevasis/ui` components -- if a published component needs a tweak, that missing capability is a bug in `@elevasis/ui`
|
|
21
21
|
|
|
22
22
|
## Silent-Break Gotchas
|
|
@@ -52,4 +52,4 @@ When building pages that display external data, use published `@elevasis/ui` com
|
|
|
52
52
|
- `operations/node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` -- sidebar composition via manifest overrides
|
|
53
53
|
- `operations/node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md` -- TypeScript shapes (`SystemModule`, `NavItem`, `OrganizationModel`)
|
|
54
54
|
- `ui/src/config/theme.ts` -- theme configuration and CSS variable definitions
|
|
55
|
-
- `ui/src/config/
|
|
55
|
+
- `ui/src/config/shell.tsx` -- the `SYSTEM_MANIFESTS` array of mounted System modules, and the seam for sidebar overrides
|
|
@@ -17,7 +17,7 @@ Organization OS is the semantic contract layer defining how organizations, Syste
|
|
|
17
17
|
- `core/config/extensions/` -- project-owned entity extension schemas
|
|
18
18
|
- `core/types/entities.ts` -- typed entity contracts (Project, Deal, etc.) extending `BaseProject` / `BaseDeal` from `@elevasis/core/entities`. Reference these from workflow input schemas -- do not redeclare them.
|
|
19
19
|
- `ui/src/routes/__root.tsx` -- wires `ElevasisSystemsProvider` with `canonicalOrganizationModel`
|
|
20
|
-
- `ui/src/app-config.ts` -- references the org model
|
|
20
|
+
- `ui/src/config/app-config.ts` -- references the org model
|
|
21
21
|
- `operations/src/index.ts` -- `DeploymentSpec` registry for workflows and agents
|
|
22
22
|
|
|
23
23
|
## Domain Overview
|
package/reference/rules/ui.md
CHANGED
|
@@ -18,18 +18,20 @@ The template frontend is a React 19 + TanStack Router app that composes a local
|
|
|
18
18
|
The main join points are:
|
|
19
19
|
|
|
20
20
|
- `ui/src/main.tsx` -- boots the app with `ElevasisUIProvider`, query client, theme config, WorkOS AuthKit, notifications, and the generated route tree
|
|
21
|
-
- `ui/src/
|
|
22
|
-
- `ui/src/
|
|
21
|
+
- `ui/src/config/shell.tsx` -- **the file you own for shell composition.** Declares the `SYSTEM_MANIFESTS` array of published System modules the shell mounts. Add, remove, or swap a System module here
|
|
22
|
+
- `ui/src/routes/__root.tsx` -- composes the authenticated shell: imports `SYSTEM_MANIFESTS` from `@/config/shell`, filters it through `selectDeclaredSystems` against `canonicalOrganizationModel`, and passes the result plus shell runtime dependencies into `ElevasisSystemsProvider` / `SystemShell`. This file is sync-managed -- edit `shell.tsx` instead
|
|
23
23
|
- `core/config/organization-model.ts` -- is the template's semantic source of truth, adapting `@elevasis/core/organization-model` into the preserved branding, dashboard label, quick-access, System labels, resource descriptors, and shell helpers
|
|
24
24
|
|
|
25
|
-
Published System modules mounted by the template shell:
|
|
25
|
+
Published System modules mounted by the template shell, in `ui/src/config/shell.tsx`'s `SYSTEM_MANIFESTS` order:
|
|
26
26
|
|
|
27
|
-
- `lead-gen
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `operations
|
|
31
|
-
- `monitoring`
|
|
32
|
-
- `
|
|
27
|
+
- `leadGenManifest` -- lead-gen
|
|
28
|
+
- `crmManifest` -- CRM
|
|
29
|
+
- `deliveryManifest` -- delivery, at `/projects`
|
|
30
|
+
- `operationsManifest` -- operations
|
|
31
|
+
- `submittedRequestsManifest` -- submitted requests, from `@elevasis/ui/features/monitoring/requests`
|
|
32
|
+
- `knowledgeManifest` -- knowledge
|
|
33
|
+
|
|
34
|
+
There is no `settings` manifest and no top-level `monitoring` manifest; settings routes are template-owned and the monitoring surface reaches the shell only through `submittedRequestsManifest`. Read `shell.tsx` rather than this list if the two disagree -- that file is the source of truth.
|
|
33
35
|
|
|
34
36
|
Important distinction:
|
|
35
37
|
|
|
@@ -42,7 +44,7 @@ Dashboard remains a host-local route at `/`, not a shared feature manifest.
|
|
|
42
44
|
This template should be treated as the downstream reference implementation for this composition:
|
|
43
45
|
|
|
44
46
|
- `core/config/organization-model.ts` owns the organization/runtime semantics
|
|
45
|
-
- `ui/src/config/
|
|
47
|
+
- `ui/src/config/shell.tsx` owns which published System modules are mounted, keeping that choice project-local instead of pushing it into `__root.tsx`
|
|
46
48
|
- `ui/src/routes/__root.tsx` threads `canonicalOrganizationModel` from `@core/config/organization-model` into `ElevasisSystemsProvider` so the shared shell/runtime uses the same semantic source of truth as the local template helpers
|
|
47
49
|
- host-local customizations still stay local: dashboard remains app-owned nav, branding stays in app config, and quick-access/dashboard UX stays in the template app
|
|
48
50
|
|
|
@@ -62,7 +64,7 @@ The app uses WorkOS AuthKit through `ElevasisUIProvider`. Authentication is enfo
|
|
|
62
64
|
|
|
63
65
|
Wrap protected route components with `ProtectedRoute` from `@elevasis/ui/features/auth`. For a **System's top-level route**, use `ProtectedSystemRoute` instead -- it is the canonical shape and is what `ui/src/routes/crm.tsx`, `lead-gen.tsx`, `monitoring.tsx`, `operations.tsx`, `projects.tsx`, `content.tsx`, and `knowledge.tsx` all ship as. See "System route guarding" below. `ProtectedRoute` on its own is for a protected route that gates on authentication alone:
|
|
64
66
|
|
|
65
|
-
`@elevasis/ui` publishes two components under this name and they behave differently. The one route files want is `@elevasis/ui/features/auth`: it wraps the base guard with an animated full-screen loader that fades out when initialization completes, and supplies a default `
|
|
67
|
+
`@elevasis/ui` publishes two components under this name and they behave differently. The one route files want is `@elevasis/ui/features/auth`: it wraps the base guard with an animated full-screen loader that fades out when initialization completes, and supplies a default `ServiceUnavailableScreen` fallback, which classifies the initialization failure and retries on a backoff instead of rendering nothing. `@elevasis/ui/auth` exports the headless base guard, whose `fallback` prop defaults to `null` -- a route that imports it and passes no `fallback` shows a blank screen for the entire initialization window and silently swallows blocking errors. Import the headless one only when the surface deliberately renders its own loading state.
|
|
66
68
|
|
|
67
69
|
```tsx
|
|
68
70
|
import { ProtectedRoute } from '@elevasis/ui/features/auth'
|
|
@@ -245,7 +247,7 @@ Section guards currently follow this pattern:
|
|
|
245
247
|
- `AccessGuard` on sections that should hard-stop when the backing System is disabled or the role lacks the permission -- `/crm` uses `accessKey="sales.crm"`, `/lead-gen` uses `"sales.lead-gen"`, `/projects` uses `"platform.projects"`, and `/operations` and `/monitoring` both use `AccessKeys.operationsRead`
|
|
246
248
|
- provider-level shell gating for shared System nav and sub-shell behavior
|
|
247
249
|
|
|
248
|
-
|
|
250
|
+
`__root.tsx` filters `SYSTEM_MANIFESTS` (imported from `@/config/shell`) through `selectDeclaredSystems` against `canonicalOrganizationModel`, so a System module only mounts when the organization model declares it, and passes `canonicalOrganizationModel` into `ElevasisSystemsProvider` so shared nav labels, paths, and graph runtime behavior resolve from the same semantic source. Visible nav is derived inside the shared shell from the declared manifests and the signed-in profile -- the template does not compute it.
|
|
249
251
|
|
|
250
252
|
## Dashboard and Feature Areas
|
|
251
253
|
|
|
@@ -280,8 +282,8 @@ The main template-owned customization surfaces are:
|
|
|
280
282
|
- `ui/src/config/theme.ts` -- theme presets and defaults
|
|
281
283
|
- `ui/src/config/background.tsx` -- shared background treatment
|
|
282
284
|
- `ui/src/config/loader.tsx` -- global loader element
|
|
283
|
-
- `ui/src/config/
|
|
284
|
-
- `core/config/organization-model
|
|
285
|
+
- `ui/src/config/shell.tsx` -- the `SYSTEM_MANIFESTS` array of published System modules the shell mounts
|
|
286
|
+
- `core/config/organization-model/` -- product labels, System availability, resource descriptors, semantic surfaces, canonical-to-legacy surface aliases, and quick-access behavior
|
|
285
287
|
- `ui/src/config/README.md` -- the deeper guide for those config files
|
|
286
288
|
|
|
287
289
|
## Customizing a Shared Full-Height Page (never wrap it)
|
|
@@ -296,11 +298,11 @@ Wrapping one of these pages in a layout element to bolt on extra UI breaks the h
|
|
|
296
298
|
|
|
297
299
|
## Customizing System Sidebars
|
|
298
300
|
|
|
299
|
-
|
|
301
|
+
`ui/src/config/shell.tsx` is where sidebar overrides go. The template ships `crmManifest` unmodified in `SYSTEM_MANIFESTS`, so there is no worked override in the template source to copy -- `shell.tsx`'s own doc comment points at `node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md` for the decision tree and patterns. A template-owned `ui/src/routes/crm/reports.tsx` route exists but is not currently surfaced by any nav override; wire it through the `items` prop or a manifest spread below, or delete it.
|
|
300
302
|
|
|
301
303
|
Two customization layers are available for every shared System sidebar:
|
|
302
304
|
|
|
303
|
-
1. **Nav-item shortcut (`items` prop)** -- when you just need to swap or extend the nav array, spread the published items constant and pass the result to `*SidebarMiddle`. The template
|
|
305
|
+
1. **Nav-item shortcut (`items` prop)** -- when you just need to swap or extend the nav array, spread the published items constant and pass the result to `*SidebarMiddle`. The template does not use this path today -- it is the shape the unwired `crm/reports.tsx` route would need.
|
|
304
306
|
|
|
305
307
|
```tsx
|
|
306
308
|
import { crmManifest, CrmSidebar, CrmSidebarMiddle, CRM_ITEMS } from '@elevasis/ui/features/crm'
|
|
@@ -39,7 +39,9 @@ The user wants to record something new -- a task, a note, a piece of information
|
|
|
39
39
|
|
|
40
40
|
The user wants to know something about current state -- task priorities, what is pending, what is running, what failed.
|
|
41
41
|
|
|
42
|
-
**Recognize by:** questions about the current list, status, or queue of things. Includes
|
|
42
|
+
**Recognize by:** questions about the current list, status, or queue of things. Includes static-model queries ("which systems are wired up?"), runtime-entity queries ("what's pending in the queue?"), and readiness diagnostics ("is content ready?"). Route Query to static-model sources (org model, Systems/Actions config), runtime sources (operations domain), or the readiness diagnostic (`om:doctor`, `/operations/systems`) based on the referenced entity.
|
|
43
|
+
|
|
44
|
+
**A System being "on" is three fields, not one.** Answering from `systems.ts`'s `enabled` alone gives the wrong answer, and the shipped template proves it: lead-gen, CRM, and `content` all read `enabled: true` while all three carry `lifecycle: 'draft'`, so none is actually reachable. `lifecycle` is the adoption switch — `draft` / `beta` / `active` / `deprecated` / `archived`, defaulting to active when absent. `enabled: false` is a deprecated short-circuit that still wins ahead of the lifecycle check, so read it too. And a System with API-backed actions needs an `apiInterface` before those actions work at all. When the question is whether a System is genuinely usable, run `om:doctor` or point the user at `/operations/systems` rather than narrating a field.
|
|
43
45
|
|
|
44
46
|
**Fixture examples:**
|
|
45
47
|
|
|
@@ -48,10 +50,21 @@ The user wants to know something about current state -- task priorities, what is
|
|
|
48
50
|
| "What should I work on next?" | Asking for prioritized task list |
|
|
49
51
|
| "What's pending in the HITL queue?" | Runtime-entity query about operations state |
|
|
50
52
|
| "What runs this week?" | Runtime query about upcoming schedules |
|
|
51
|
-
| "
|
|
53
|
+
| "Which systems are actually wired up?" | Static-model query about System adoption |
|
|
52
54
|
| "What's waiting on review?" | Runtime-entity query about content review-gate state |
|
|
55
|
+
| "Where did this go out?" | Distribution-row query -- which targets were written |
|
|
56
|
+
| "What platforms did this ship to?" | Distribution-row query, phrased by destination |
|
|
57
|
+
| "What are the steps in this pipeline?" | Pipeline step-contract query |
|
|
58
|
+
| "What review gates does this pipeline have?" | Pipeline step-contract query, phrased by gate |
|
|
59
|
+
| "Is the content system ready?" | Readiness diagnosis, not a config read |
|
|
60
|
+
|
|
61
|
+
**Agent action:** read the relevant source and narrate the answer in plain language. Use org model or `project:*` for project state, `elevasis-sdk queue:list --status pending --pretty` and `queue:status --pretty` for HITL queue state, `elevasis-sdk schedule:list --status active --pretty` for upcoming recurring automation, and for the content platform: `elevasis-sdk content:queue --pretty` (open review gates), `content:list --pretty` (item overview), `content:board <pipelineId> --pretty` (pipeline state), `content:get <itemId> --pretty` (one item's attempt/distribution history), `content:distributions --pretty` (distribution rows, one per platform/format target per item), `content:pipeline [id] --pretty` (pipeline templates, or one pipeline's step contract), `content:source-assets --pretty` (list available source assets), or `content:source-asset <id> --pretty` (one source asset's detail). No writes.
|
|
62
|
+
|
|
63
|
+
**`content:distributions` vs `content:get`.** They overlap and the distinction is worth keeping straight: `content:get <itemId>` answers _what happened to this item_; `content:distributions` answers _what went out across the pipeline_ — a filterable cross-item read the per-item command cannot do. It takes `--content-item-id`, `--pipeline-id`, `--platform`, `--status`, `--limit`, and `--offset`.
|
|
64
|
+
|
|
65
|
+
**`content:pipeline` reads the deployed snapshot, not your local model.** With no id it lists pipeline templates; with an id it returns that pipeline's step contract (step keys and review modes). It reads the **deployed** Organization Model snapshot, so a model edit that was never redeployed returns a stale-snapshot **503**. That is a missing redeploy, not a platform failure — do not report it as a bug. `content:pipeline <id>` is also the most direct way to resolve a step key before `content:review --step`; the Transition intent says never to guess `--step`, and this is the second route to getting it right (`content:queue` is the other).
|
|
53
66
|
|
|
54
|
-
**
|
|
67
|
+
**Readiness is a diagnostic read, and it belongs here.** `elevasis-sdk om:doctor` is the answer to "is this System actually usable" — it reports per-issue readiness diagnostics against the deployed snapshot, where plain `doctor` prints only the compact roster. Reach for it whenever a question is about whether something is _wired up_ rather than what the model _says_. A tenant can also read the same picture in the UI at `/operations/systems`, which every project mounts.
|
|
55
68
|
|
|
56
69
|
### 3. Describe
|
|
57
70
|
|
|
@@ -97,7 +110,7 @@ The user wants to change the status of a task or entity.
|
|
|
97
110
|
| "Pause the Friday report" | Changes schedule state |
|
|
98
111
|
| "Approve this post" | Clears a named content review gate |
|
|
99
112
|
|
|
100
|
-
**Agent action:** identify the task, queue item, schedule, or entity being transitioned, confirm the new status/action with the user, then apply it via `elevasis-sdk project:task:save`, `elevasis-sdk queue:select <id> --action-id <id>`, `elevasis-sdk queue:expire <id>`, `elevasis-sdk schedule:pause <id>`, `schedule:resume <id>`, `schedule:cancel <id>`, or `elevasis-sdk content:review <itemId> --step <key> (--approve | --reject) --user <email>` as appropriate. `content:review` always requires resolving the exact `stepKey`
|
|
113
|
+
**Agent action:** identify the task, queue item, schedule, or entity being transitioned, confirm the new status/action with the user, then apply it via `elevasis-sdk project:task:save`, `elevasis-sdk queue:select <id> --action-id <id>`, `elevasis-sdk queue:expire <id>`, `elevasis-sdk schedule:pause <id>`, `schedule:resume <id>`, `schedule:cancel <id>`, or `elevasis-sdk content:review <itemId> --step <key> (--approve | --reject) --user <email>` as appropriate. `content:review` always requires resolving the exact `stepKey` first and confirming the item/decision before executing -- never guess `--step`. Two commands resolve it: `content:queue` (what is currently open) and `content:pipeline <id>` (the pipeline's declared step contract, which is the more direct route when you know the pipeline). Never auto-transition without confirmation if the target entity is ambiguous.
|
|
101
114
|
|
|
102
115
|
### 5. Navigate
|
|
103
116
|
|
|
@@ -112,6 +125,7 @@ The user wants to shift focus -- to a different task, project, System, Action, o
|
|
|
112
125
|
| "Let's focus on the onboarding flow for now" | "Focus on" + scope target |
|
|
113
126
|
| "Switch to the Shopify integration project" | "Switch to" = navigate to a different project scope |
|
|
114
127
|
| "Back to the CRM tasks" | "Back to" = return to a prior scope |
|
|
128
|
+
| "Open the systems page" | "Open" + a real route -- `/operations/systems` |
|
|
115
129
|
|
|
116
130
|
**Agent action:** update the active scope in `prj_tasks.resume_context` (current project + task pointer), then narrate the new scope in plain language so the user knows where they are.
|
|
117
131
|
|
|
@@ -158,7 +172,9 @@ For "build/extend lead gen" / "campaign creator" / "outbound list state" asks, c
|
|
|
158
172
|
|
|
159
173
|
For "add a custom CRM action" / "Send Quote button" asks, classify as Codify, then read `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/customize-crm-actions.md` before editing. Start with the shared `crmActions` provider path for action visibility, labels, ordering, and render-time configuration. In v1, platform-known/default action endpoint behavior is server-constrained; use project-owned UI that calls the workflow directly when a custom key sits outside that server-dispatched set.
|
|
160
174
|
|
|
161
|
-
For "build/extend content" / "add a content pipeline" / "content review screen" asks, classify the structural org-model portion as Codify, then read `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/extend-content.md` before editing. A content pipeline is a catalog record, not code -- content work often spans org-model pipeline/step/status/pillar catalogs, the `content` workflow adapter,
|
|
175
|
+
For "build/extend content" / "add a content pipeline" / "content review screen" asks, classify the structural org-model portion as Codify, then read `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/extend-content.md` before editing. A content pipeline is a catalog record, not code -- content work often spans org-model pipeline/step/status/pillar catalogs, the `content` workflow adapter, the tenant's own Workspace screens, and distribution tracking; do not reduce it to only catalog config or only UI.
|
|
176
|
+
|
|
177
|
+
**Know which side of the line the ask falls on before routing it.** `extend-content.md`'s "Own the Workspace" section draws it: **you own the surfaces where content is operated on; the platform owns the surfaces where it is observed.** Creating a piece and clearing its review gates are yours — authored as the tenant's own Workspace screens, reached through `workspaceRoute` at the pipeline and step level and composed with `ContentWorkspaceShell`. The board, items list, attempt history, distributions, and cross-pipeline review queue are shared, display-only, and do not write. So "build a content review screen" is a **tenant Workspace** build, not a customization of shared review-page composition -- building it on the platform side puts it on the wrong side of a line the recipe now forbids.
|
|
162
178
|
|
|
163
179
|
Heuristics for when to propose codification (passed to `/om` as context):
|
|
164
180
|
|
|
@@ -183,6 +199,11 @@ The user wants to enable or disable a System.
|
|
|
183
199
|
|
|
184
200
|
**Agent action:** delegate to `/om systems`. The ceremony (confirm + edit `core/config/organization-model/systems.ts` -- or `core/config/organization-model.ts` in unsplit projects -- + typecheck) belongs to `/om`, not to the ambient rule.
|
|
185
201
|
|
|
202
|
+
**Check adoption before flipping anything — `lifecycle` is the switch, not `enabled`.** Run `om:doctor` (or read `/operations/systems`) first and pass what it says to `/om` as context. Two things go wrong without that check:
|
|
203
|
+
|
|
204
|
+
- **"Turn on X" actioned against `enabled`** does nothing when `enabled` is already `true`, which it is for every template System. The field the user means is `lifecycle`.
|
|
205
|
+
- **Flipping `lifecycle: 'draft'` to `'active'` on an unadopted System produces guaranteed 503s.** A System with no scoped resources and no `apiInterface` computes as ready and then fails every request. "On" means adopted — resources, ontology, and an `apiInterface` where API-backed actions are involved — not one edited field. If the readiness check says the System is not adopted, say so in plain language instead of making it look enabled.
|
|
206
|
+
|
|
186
207
|
**Tenant-local only.** Toggle operates on this project's own `core/config/organization-model/systems.ts` (or `core/config/organization-model.ts` in unsplit projects) — the project's own Systems. The Elevasis platform's own Systems are not in scope; this project cannot toggle them and vibe must not pretend it can. If a user names a platform-only System, surface the boundary in plain language rather than attempting a toggle.
|
|
187
208
|
|
|
188
209
|
### 8. Operate
|
|
@@ -271,4 +292,5 @@ Layers 2 (Public API), 3 (UI Shell Runtime), 5 (Toolkit), and 6 (Graph) require
|
|
|
271
292
|
- `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/extend-lead-gen.md` -- lead-gen build/extend scope
|
|
272
293
|
- `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/customize-crm-actions.md` -- custom CRM action keys and the `crmActions` provider
|
|
273
294
|
- `operations/node_modules/@elevasis/sdk/reference/scaffold/recipes/extend-content.md` -- content build/extend scope
|
|
274
|
-
- `core/config/organization-model/systems.ts` -- label vocabulary and System availability (or `core/config/organization-model.ts` in unsplit projects)
|
|
295
|
+
- `core/config/organization-model/systems.ts` -- label vocabulary, and the `lifecycle` / `enabled` / `apiInterface` fields a System's availability is read from (or `core/config/organization-model.ts` in unsplit projects). Read `elevasis-sdk om:doctor` rather than this file when the question is whether a System is genuinely adopted
|
|
296
|
+
- `/operations/systems` -- the readiness page every project mounts, showing which Systems are actually wired up
|
package/reference/rules/vibe.md
CHANGED
|
@@ -21,7 +21,7 @@ Vibe is **ambient and always on**. Every natural-language message is silently cl
|
|
|
21
21
|
| Transition | "done", "stuck", "blocked", "finished", "complete", "approve", "pause" | Agent -- confirm + `project:task:save`, `queue:select`, `schedule:*`, or `content:review` |
|
|
22
22
|
| Navigate | "focus on", "switch to", "back to", "look at" | Agent -- update scope + narrate |
|
|
23
23
|
| Codify | "we are X", "we track Y", repeated attribute, "add type/field" | Delegate to `/om \<domain>` |
|
|
24
|
-
| Toggle | "enable", "disable", "turn on/off" + system |
|
|
24
|
+
| Toggle | "enable", "disable", "turn on/off" + system | Check adoption (`om:doctor`), then delegate to `/om systems` (tenant-local only) |
|
|
25
25
|
| Operate | "run", "execute", "launch", "trigger", "kick off", "start" + deployed resource | Delegate to `/elevasis` -- `elevasis-sdk describe` + confirm + `elevasis-sdk exec` |
|
|
26
26
|
|
|
27
27
|
## Safety Boundaries
|
|
@@ -31,6 +31,7 @@ Vibe is **ambient and always on**. Every natural-language message is silently cl
|
|
|
31
31
|
- **Never write the model yourself.** Codify and Toggle detect intent and delegate to `/om <domain>`; the draft-confirm-write-typecheck ceremony belongs to `/om`.
|
|
32
32
|
- **Never flip public agent exposure.** Making a deployed agent reachable on the public internet (the `agent_access_grants` row behind `/public/agents/:slug`, managed via `grant:create` / `grant:update` / `grant:disable` or the Resource-page public/private toggle) is a security boundary deliberately kept out of ambient routing -- a non-technical user describing their business must never expose an agent by accident. Do NOT classify "make my agent public" / "put the interview online" as Toggle, and do NOT auto-execute. Surface the `grant:*` CLI or the Resource-page toggle in plain language and require explicit confirmation.
|
|
33
33
|
- **Toggle is tenant-local.** It edits this project's own Systems config -- `core/config/organization-model/systems.ts`, or `core/config/organization-model.ts` in unsplit projects -- only. The Elevasis platform's own Systems cannot be toggled from here; surface that boundary rather than attempting it.
|
|
34
|
+
- **"On" is `lifecycle`, and it is not the whole story.** `enabled` is already `true` on every template System, so actioning "turn on X" against it does nothing; `lifecycle` (`draft` / `beta` / `active` / ...) is the switch. But flipping `lifecycle` to `'active'` on a System with no scoped resources and no `apiInterface` makes it compute as ready and then 503 every request. Run `om:doctor` (or read `/operations/systems`) before delegating, and pass the result to `/om` as context. If the System is not adopted, say so rather than making it look enabled.
|
|
34
35
|
- **Never guess an ambiguous intent.** Ask one neutral clarifying question presenting the plausible intents. Do not apply a precedence rule and do not route to the "closest" match.
|
|
35
36
|
- **Never invent vocabulary.** Status, entity, and layer names come from the model's inline `label` fields, read verbatim -- never hardcoded synonyms.
|
|
36
37
|
|
|
@@ -64,4 +65,4 @@ a required question on every System-shaping change.
|
|
|
64
65
|
## References
|
|
65
66
|
|
|
66
67
|
- `operations/node_modules/@elevasis/sdk/reference/rules/vibe-intents.md` -- per-intent recognition signals, fixture examples, exact agent actions, stage/state sub-routing, the classifier threshold, and phase scope
|
|
67
|
-
- `core/config/organization-model/systems.ts` -- label vocabulary and System availability (or `core/config/organization-model.ts` in unsplit projects)
|
|
68
|
+
- `core/config/organization-model/systems.ts` -- label vocabulary, and the `lifecycle` / `enabled` / `apiInterface` fields a System's availability is read from (or `core/config/organization-model.ts` in unsplit projects). Run `elevasis-sdk om:doctor`, or read `/operations/systems`, when the question is whether a System is genuinely adopted rather than what the file says
|
|
@@ -101,25 +101,38 @@ The external skill doc (`.claude/skills/external/SKILL.md`) remains the workflow
|
|
|
101
101
|
|
|
102
102
|
### Per-Project Checks (auto-discovered)
|
|
103
103
|
|
|
104
|
-
| Category
|
|
105
|
-
|
|
|
106
|
-
| `deps`
|
|
107
|
-
| `
|
|
108
|
-
| `org-os`
|
|
109
|
-
| `placeholders`
|
|
110
|
-
| `scripts`
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
104
|
+
| Category | What It Checks |
|
|
105
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
106
|
+
| `deps` | `@elevasis/ui`, `@elevasis/sdk`, `@elevasis/core` versions match template |
|
|
107
|
+
| `registry-owned` | registry-backed `replace` surfaces match the template byte-for-byte where verification still models them as exact baselines |
|
|
108
|
+
| `org-os` | Organization model exists, exports canonical symbols, imports from `@elevasis/core/organization-model`, either calls `createFoundationOrganizationModel` or uses explicit `resolveOrganizationModel(..., { mergeDefaults: false })` canonical assembly, app-config references org model, `__root.tsx` uses `ElevasisAuthenticatedShell` / `ElevasisSystemsProvider` + `canonicalOrganizationModel`, `main.tsx` uses `createElevasisApp`, all 3 CSS subpath imports present |
|
|
109
|
+
| `placeholders` | No unresolved `__PROJECT_SLUG__`, `__PROJECT_NAME__`, `__PROJECT_DESCRIPTION__` in key config files |
|
|
110
|
+
| `scripts` | `ui` and `operations` `package.json` have required npm scripts |
|
|
111
|
+
| `shared` | Five shared directories exist with minimum file counts: `ui/src/lib` (3), `ui/src/test-utils` (2), `ui/src/config` (3), `ui/src/routes` (5), `ui/src/features` (5) |
|
|
112
|
+
| `sync-plan` | Registry planner drift -- what the planner would write, and whether project-owned paths stay outside its scope |
|
|
113
|
+
| `project-marker` | The project's `.elevasis` marker file is present and well-formed |
|
|
114
|
+
| `claude` | `.claude/` infrastructure -- skills, rules, hooks, and settings the tenant agent loads |
|
|
115
|
+
| `knowledge` | Knowledge scaffold wiring and its generated nodes |
|
|
116
|
+
| `resource-governance` | Resource governance wiring resolves against the project's own OM |
|
|
117
|
+
| `contract-conformance` | Operations-bundle conformance via `detect-conformance-gaps.ts`; passes silently when the bundle is absent |
|
|
118
|
+
| `retired-nav` | Retired nav-item surfaces have not come back |
|
|
119
|
+
| `conflicts` | No merge conflict markers in source files |
|
|
120
|
+
| `git` | Working tree is clean |
|
|
121
|
+
| `lockfile` | `pnpm-lock.yaml` and `node_modules` exist |
|
|
122
|
+
|
|
123
|
+
An org-specific project (one not derived from the template) reports a single `mode` pass and skips the
|
|
124
|
+
dependency and `registry-owned` UI checks entirely.
|
|
116
125
|
|
|
117
126
|
### Monorepo-Level Checks
|
|
118
127
|
|
|
119
|
-
| Category
|
|
120
|
-
|
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
128
|
+
| Category | What It Checks |
|
|
129
|
+
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
130
|
+
| `monorepo/artifacts` | Four hardcoded generated artifacts plus every registry-derived `generated` dependent exist and are non-empty |
|
|
131
|
+
| `monorepo/tombstones` | Tombstone lifecycle. A discharged tombstone warns rather than fails -- stale housekeeping should not turn the gate red |
|
|
132
|
+
| `monorepo/template-coverage` | Every file under `external/_template` is claimed by some registry entry |
|
|
133
|
+
| `monorepo/stale-prose-paths` | Prose in managed surfaces does not cite paths that no longer exist |
|
|
134
|
+
| `monorepo/external-registry` | The external registry's own status |
|
|
135
|
+
| `registry-owned/contract` | Every byte-equality-checked path is `replace`-category. Runs once per invocation, not per project |
|
|
123
136
|
|
|
124
137
|
### Usage
|
|
125
138
|
|
|
@@ -138,13 +151,14 @@ pnpm sync:verify -- nirvana-marketing # Single project
|
|
|
138
151
|
|
|
139
152
|
### Planner Interpretation Note
|
|
140
153
|
|
|
141
|
-
`pnpm sync:verify`
|
|
154
|
+
`pnpm sync:verify` no longer emits `tier1` / `tier3` labels at all — the categories in the tables above are the real ones, and the ownership semantics come from the registry-backed categories used by the planner:
|
|
142
155
|
|
|
143
156
|
- `.claude/skills/**`, `hooks/**`, `rules/**`, `scripts/**`, and `.claude/settings.json` are managed `replace` surfaces
|
|
144
|
-
- `
|
|
157
|
+
- `.elevasis`, `core/config/organization-model/profile.ts`, `operations/src/**`, `shared/src/**`, `CLAUDE.md`, and extension files are `never-touch`
|
|
158
|
+
- `ui/src/config/shell.tsx` is the project-owned shell seam. It carries no `never-touch` rule -- it is annotated `critical-manual-merge`, which is advisory, so edit it freely and expect a catch-up warning rather than a revert. `ui/src/routes/__root.tsx` and `ui/src/main.tsx` are the sync-managed files it was extracted from; put per-project shell customization in `shell.tsx`, not in those two
|
|
145
159
|
- generated surfaces are verified for freshness, not copied
|
|
146
160
|
|
|
147
|
-
|
|
161
|
+
The old `Tier 1` / `Tier 2` / `Tier 3` vocabulary survives only in this doc's history and in operator memory. Do not expect it in verifier output, and do not reintroduce it as shorthand — the registry categories are the canonical execution contract.
|
|
148
162
|
|
|
149
163
|
---
|
|
150
164
|
|
|
@@ -119,7 +119,7 @@ The output lands in `packages/sdk/reference/` which is included in the npm packa
|
|
|
119
119
|
- UI patterns: `packages/ui/src/scaffold/...`
|
|
120
120
|
- Cross-package or SDK-owned: `packages/sdk/docs/scaffold/...`
|
|
121
121
|
|
|
122
|
-
2. **Add to `SCAFFOLD_COPIES
|
|
122
|
+
2. **Add to the base `SCAFFOLD_COPIES` list** in `scripts/monorepo/scaffold-copies.js`. Do **not** edit the `SCAFFOLD_COPIES` constant in `packages/sdk/scripts/copy-reference-docs.mjs` -- that one is composed (`[...BASE_SCAFFOLD_COPIES, ...RULE_REFERENCE_COPIES]`) from two imported lists, so an entry added there is lost the next time either source list is edited:
|
|
123
123
|
|
|
124
124
|
```javascript
|
|
125
125
|
{ source: 'packages/sdk/docs/scaffold/operations/my-doc.md', target: 'scaffold/operations/my-doc.md' }
|
|
@@ -12,7 +12,7 @@ CRM deal pages derive their action buttons from an `ActionDef[]` array. The shar
|
|
|
12
12
|
|
|
13
13
|
For the broader CRM extension map -- pages, sidebars, hooks, workflow adapters, System Interfaces, and org-model boundaries -- start with [Build and Extend CRM](extend-crm.md). This recipe is only the deal-action path.
|
|
14
14
|
|
|
15
|
-
**Shape reference:** The `ActionDef` flat shape and the consolidation that replaced the old `handler`/`kind` union are documented in `apps/docs/content/docs/
|
|
15
|
+
**Shape reference:** The `ActionDef` flat shape and the consolidation that replaced the old `handler`/`kind` union are documented in `apps/docs/content/docs/technical/features/operations/crm/index.mdx`.
|
|
16
16
|
|
|
17
17
|
Use this recipe when a user asks for work like:
|
|
18
18
|
|
|
@@ -348,8 +348,8 @@ Everything you need to build a combined create-and-review screen is already expo
|
|
|
348
348
|
`resolveContentStepResource`.
|
|
349
349
|
|
|
350
350
|
**`Workspace` is a fixed platform label and is not vocabulary-driven.** Rename the page, not the
|
|
351
|
-
section. (The section was called `Create` before 2026-08-15. `createItems`
|
|
352
|
-
deprecated alias
|
|
351
|
+
section. (The section was called `Create` before 2026-08-15. The `createItems` prop was renamed to
|
|
352
|
+
`workspaceItems`; the deprecated alias has since been removed, so `workspaceItems` is the only name.)
|
|
353
353
|
|
|
354
354
|
### Point the shared pages at your Workspace
|
|
355
355
|
|
|
@@ -67,7 +67,7 @@ Deal list and detail responses include a server-derived `priority` object. Use `
|
|
|
67
67
|
For a simple nav addition, extend `CRM_ITEMS` and override the CRM system manifest:
|
|
68
68
|
|
|
69
69
|
```tsx
|
|
70
|
-
// ui/src/
|
|
70
|
+
// ui/src/config/shell.tsx
|
|
71
71
|
import { crmManifest, CRM_ITEMS, CrmSidebar, CrmSidebarMiddle } from '@elevasis/ui/features/crm'
|
|
72
72
|
import type { SystemModule } from '@elevasis/ui/provider'
|
|
73
73
|
import type { NavItem } from '@elevasis/ui/layout'
|
|
@@ -90,7 +90,9 @@ export const customCrmManifest: SystemModule = {
|
|
|
90
90
|
}
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
Then replace `crmManifest` with `customCrmManifest` in the
|
|
93
|
+
Then replace `crmManifest` with `customCrmManifest` in the `SYSTEM_MANIFESTS` array — which is declared in this same file, `ui/src/config/shell.tsx` — and add the matching route under `ui/src/routes/crm/`.
|
|
94
|
+
|
|
95
|
+
**Do this in `shell.tsx`, not in `ui/src/routes/__root.tsx`.** `__root.tsx` imports `SYSTEM_MANIFESTS` from `@/config/shell` and filters it through `selectDeclaredSystems`; it does not declare the array. It is also `replace`-category with a `replace-all` strategy, so anything you write into it is overwritten outright on the next sync -- not preserved, not merged, not flagged. `shell.tsx` is the seam that exists for exactly this edit.
|
|
94
96
|
|
|
95
97
|
For structural changes, compose `CrmSidebarTop`, `SubshellNavList`, `SubshellSidebarSection`, `MyTasksPanel`, and `QuickCreateActions`. The full sidebar decision tree lives in `operations/node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
|
|
96
98
|
|
|
@@ -73,7 +73,7 @@ Look for the **Lead Gen Platform Primitives** section. It includes list shapes,
|
|
|
73
73
|
For a simple nav addition, extend `LEAD_GEN_ITEMS` and override the lead-gen system manifest:
|
|
74
74
|
|
|
75
75
|
```tsx
|
|
76
|
-
// ui/src/
|
|
76
|
+
// ui/src/config/shell.tsx
|
|
77
77
|
import { leadGenManifest, LEAD_GEN_ITEMS, LeadGenSidebar, LeadGenSidebarMiddle } from '@elevasis/ui/features/lead-gen'
|
|
78
78
|
import type { SystemModule } from '@elevasis/ui/provider'
|
|
79
79
|
import type { NavItem } from '@elevasis/ui/layout'
|
|
@@ -96,7 +96,9 @@ export const customLeadGenManifest: SystemModule = {
|
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
Then replace `leadGenManifest` with `customLeadGenManifest` in the
|
|
99
|
+
Then replace `leadGenManifest` with `customLeadGenManifest` in the `SYSTEM_MANIFESTS` array — which is declared in this same file, `ui/src/config/shell.tsx` — and add the matching route under `ui/src/routes/lead-gen/`.
|
|
100
|
+
|
|
101
|
+
**Do this in `shell.tsx`, not in `ui/src/routes/__root.tsx`.** `__root.tsx` imports `SYSTEM_MANIFESTS` from `@/config/shell` and filters it through `selectDeclaredSystems`; it does not declare the array. It is also `replace`-category with a `replace-all` strategy, so anything you write into it is overwritten outright on the next sync -- not preserved, not merged, not flagged. `shell.tsx` is the seam that exists for exactly this edit.
|
|
100
102
|
|
|
101
103
|
For structural changes, compose `LeadGenSidebarTop`, `SubshellNavList`, and `SubshellSidebarSection`. The full sidebar decision tree lives in `operations/node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
|
|
102
104
|
|
|
@@ -185,14 +187,18 @@ const App = createElevasisApp({
|
|
|
185
187
|
```
|
|
186
188
|
|
|
187
189
|
```tsx
|
|
188
|
-
// ui/src/routes/__root.tsx
|
|
190
|
+
// ui/src/routes/__root.tsx (sync-managed — shown for reference, not for editing)
|
|
189
191
|
import { ElevasisAuthenticatedShell } from '@elevasis/ui/app'
|
|
190
192
|
import { canonicalOrganizationModel } from '@core/config/organization-model'
|
|
193
|
+
import { selectDeclaredSystems } from '@elevasis/ui/provider'
|
|
194
|
+
import { SYSTEM_MANIFESTS } from '@/config/shell'
|
|
195
|
+
|
|
196
|
+
const DECLARED_SYSTEM_MANIFESTS = selectDeclaredSystems(SYSTEM_MANIFESTS, canonicalOrganizationModel)
|
|
191
197
|
|
|
192
|
-
|
|
198
|
+
function RootLayoutComponent() {
|
|
193
199
|
return (
|
|
194
200
|
<ElevasisAuthenticatedShell
|
|
195
|
-
systems={
|
|
201
|
+
systems={DECLARED_SYSTEM_MANIFESTS}
|
|
196
202
|
organizationModel={canonicalOrganizationModel}
|
|
197
203
|
// other shell config...
|
|
198
204
|
/>
|
|
@@ -264,6 +270,7 @@ const listActions: ListBuilderRegistry = [
|
|
|
264
270
|
}
|
|
265
271
|
]
|
|
266
272
|
|
|
273
|
+
// Declared in ui/src/config/shell.tsx and imported here.
|
|
267
274
|
const SYSTEM_MANIFESTS = [
|
|
268
275
|
leadGenManifest,
|
|
269
276
|
// Add any other shared/local system manifests here.
|
|
@@ -493,6 +500,28 @@ export const organizationModel = {
|
|
|
493
500
|
}
|
|
494
501
|
```
|
|
495
502
|
|
|
503
|
+
### Which authoring shape to use
|
|
504
|
+
|
|
505
|
+
Two shapes exist and the readiness profile decides which one you get.
|
|
506
|
+
|
|
507
|
+
**Adopting one of the platform's catalogued profiles** — `SYSTEM_INTERFACE_PROFILES` holds four: `sales.lead-gen.api`, `sales.crm.api`, and `sales.lead-gen.crm-handoff`, which are the three built-in-validated ones, plus `content.api`, which is contract-validated. All four go through the helper — use the `defineSystemApiInterface` helper from `@elevasis/core/organization-model`, not a hand-written literal. It is what `pnpm elevasis-sdk om:emit-api-interface` generates, so the helper keeps your hand-authored System and your scaffolded one the same shape:
|
|
508
|
+
|
|
509
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import { defineSystemApiInterface } from '@elevasis/core/organization-model'
|
|
513
|
+
|
|
514
|
+
export const prospectingApiInterface = defineSystemApiInterface({
|
|
515
|
+
systemPath: 'sales.lead-gen',
|
|
516
|
+
readinessProfile: 'sales.lead-gen.api',
|
|
517
|
+
resourceIds: ['acme-list-build-workflow', 'acme-list-export-workflow']
|
|
518
|
+
})
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The helper throws at declaration time on the failure modes the literal lets through silently — most importantly an **empty `resourceIds`**, which otherwise computes as ready and then 503s every request. That is why `resourceIds` is typed `[string, ...string[]]`. **"No scoped resources" means omit the `apiInterface` block entirely**, never hand-write one with an empty list.
|
|
522
|
+
|
|
523
|
+
**Declaring a custom `readinessProfile`**, as the `acme.prospecting.api` block above does, the helper is not available to you: it validates `readinessProfile` against `SYSTEM_INTERFACE_PROFILES` — a platform-owned catalog in `@elevasis/core` — and throws on anything outside it. A custom profile therefore stays a hand-written literal, and its `readinessContract` is mandatory for the reason given above. Do not add your id to `SYSTEM_INTERFACE_PROFILES`; that is platform source, not tenant source.
|
|
524
|
+
|
|
496
525
|
`readinessContract.requiredObjects` and `requiredCatalogs` are arrays of ontology IDs owned by this system. The platform validates that each declared object type exists in the OM and that each declared catalog type has at least one entry. `requiredCatalogs` must declare at least one entry — an empty contract asserts nothing and is rejected.
|
|
497
526
|
|
|
498
527
|
Built-in profile ids (`sales.lead-gen.api`, etc.) derive their requirements from platform code. **A `readinessContract` declared alongside a built-in profile is ignored outright — not merely unnecessary.** The readiness engine branches on the profile: a registered built-in runs its own validator, and the authored contract is read only on the `else` branch, so anything you declare next to a built-in profile validates nothing and silently drifts from what the platform actually enforces. Real projects have shipped full contracts this way believing they were enforced.
|
|
@@ -28,10 +28,10 @@ There is one pattern for customizing a system's sidebar or pages: set `sidebar`
|
|
|
28
28
|
|
|
29
29
|
Extend CRM's nav by spreading `CRM_ITEMS` and appending a Reports entry. Pass the extended array to `CrmSidebarMiddle`.
|
|
30
30
|
|
|
31
|
-
Wire the override in `ui/src/routes/__root.tsx
|
|
31
|
+
Wire the override in `ui/src/config/shell.tsx`, the customization seam that owns the manifest list. `ui/src/routes/__root.tsx` imports `SYSTEM_MANIFESTS` from there and filters it through `selectDeclaredSystems` before mounting, so a manifest whose System the org model does not declare is dropped automatically.
|
|
32
32
|
|
|
33
33
|
```tsx
|
|
34
|
-
// ui/src/
|
|
34
|
+
// ui/src/config/shell.tsx (excerpt -- add after existing imports)
|
|
35
35
|
|
|
36
36
|
import { crmManifest, CrmSidebar, CrmSidebarMiddle, CRM_ITEMS } from '@elevasis/ui/features/crm'
|
|
37
37
|
import { IconFileText } from '@tabler/icons-react'
|
|
@@ -58,13 +58,13 @@ Then swap `crmManifest` for `customCrmManifest` in the `SYSTEM_MANIFESTS` array:
|
|
|
58
58
|
|
|
59
59
|
```tsx
|
|
60
60
|
// In the SYSTEM_MANIFESTS array (same file)
|
|
61
|
-
const SYSTEM_MANIFESTS: SystemModule[] = [
|
|
61
|
+
export const SYSTEM_MANIFESTS: SystemModule[] = [
|
|
62
62
|
leadGenManifest,
|
|
63
63
|
customCrmManifest, // <-- replaces crmManifest
|
|
64
64
|
deliveryManifest,
|
|
65
65
|
operationsManifest,
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
submittedRequestsManifest,
|
|
67
|
+
knowledgeManifest
|
|
68
68
|
]
|
|
69
69
|
```
|
|
70
70
|
|
|
@@ -15,7 +15,7 @@ Create `ui/src/routes/my-system.index.tsx`:
|
|
|
15
15
|
```tsx
|
|
16
16
|
import { createFileRoute } from '@tanstack/react-router'
|
|
17
17
|
import { ProtectedRoute } from '@/features/auth'
|
|
18
|
-
import {
|
|
18
|
+
import { AppPageLayout } from '@elevasis/ui/layout'
|
|
19
19
|
import { MySystemPage } from '@/features/my-system/components/MySystemPage'
|
|
20
20
|
|
|
21
21
|
export const Route = createFileRoute('/my-system/')({
|
|
@@ -25,18 +25,18 @@ export const Route = createFileRoute('/my-system/')({
|
|
|
25
25
|
function MySystemRouteComponent() {
|
|
26
26
|
return (
|
|
27
27
|
<ProtectedRoute>
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
<MySystemPage />
|
|
32
|
-
</PageContainer>
|
|
33
|
-
</AppShellContentContainer>
|
|
34
|
-
</AppTopbarAdjusterWrapper>
|
|
28
|
+
<AppPageLayout>
|
|
29
|
+
<MySystemPage />
|
|
30
|
+
</AppPageLayout>
|
|
35
31
|
</ProtectedRoute>
|
|
36
32
|
)
|
|
37
33
|
}
|
|
38
34
|
```
|
|
39
35
|
|
|
36
|
+
`AppPageLayout` is the standard route shell — topbar offset, the shell's padded content region, then the page container. It replaced the hand-written three-component nesting of `AppTopbarAdjusterWrapper` / `AppShellContentContainer` / `PageContainer`; do not write that nesting yourself. Pass `contained={false}` for a page that manages its own width (the monitoring dashboards do, since their charts run full-bleed) — that prop is the escape hatch, not a re-nest.
|
|
37
|
+
|
|
38
|
+
For a page that sits inside a **subshell sidebar**, use `SubshellPageLayout` from the same subpath instead. The two are mutually exclusive: `AppPageLayout` pushes the whole main region down, while the subshell applies the topbar offset to the scrolling right side only so the sidebar starts at the top. Nesting one in the other double-pads the page and breaks the `height: 100%` chain, so the inner scroll never engages. A subshell page that must run full-bleed renders `SubshellContentContainer` directly — there is deliberately no `contained` prop on `SubshellPageLayout`.
|
|
39
|
+
|
|
40
40
|
Add the sidebar entry as a system node in `core/config/organization-model.ts`:
|
|
41
41
|
|
|
42
42
|
`systems` is an id-keyed record, not an array, and `order` is required on every entry:
|
|
@@ -68,13 +68,9 @@ function MySystemRouteComponent() {
|
|
|
68
68
|
return (
|
|
69
69
|
<ProtectedRoute>
|
|
70
70
|
<AccessGuard accessKey="my-system">
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
<MySystemPage />
|
|
75
|
-
</PageContainer>
|
|
76
|
-
</AppShellContentContainer>
|
|
77
|
-
</AppTopbarAdjusterWrapper>
|
|
71
|
+
<AppPageLayout>
|
|
72
|
+
<MySystemPage />
|
|
73
|
+
</AppPageLayout>
|
|
78
74
|
</AccessGuard>
|
|
79
75
|
</ProtectedRoute>
|
|
80
76
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Integration Adapters"
|
|
3
|
-
description: "Auto-generated table of all
|
|
3
|
+
description: "Auto-generated table of all 14 integration (credential-bound) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the INTEGRATION_EXPORTS list in the generator, checked against the adapter directory on every run."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
{/* @generated by .claude/_gen/sync-sdk-adapters.ts — DO NOT EDIT */}
|
|
@@ -16,6 +16,7 @@ Integration adapters use a factory pattern. Call `create*Adapter(credential)` wi
|
|
|
16
16
|
| Dropbox | `createDropboxAdapter(credential)` | `uploadFile`, `createFolder`, `listFolder`, `getMetadata`, `getTemporaryLink`, `createSharedLink`, `download`, `getThumbnail`, `getThumbnailBatch` | Dropbox — upload files and create folders. |
|
|
17
17
|
| Gmail | `createGmailAdapter(credential)` | `sendEmail` | Gmail — send emails via a bound Gmail credential. |
|
|
18
18
|
| GoogleSheets | `createGoogleSheetsAdapter(credential)` | `readSheet`, `writeSheet`, `appendRows`, `clearRange`, `getSpreadsheetMetadata`, `batchUpdate`, `getHeaders`, `getLastRow`, `getRowByValue`, `updateRowByValue`, `upsertRow`, `filterRows`, `deleteRowByValue` | Google Sheets — read, write, append, filter, and manage spreadsheet data. |
|
|
19
|
+
| Instagram | `createInstagramAdapter(credential)` | `createMediaContainer`, `createCarouselContainer`, `publishContainer`, `getContainerStatus`, `getMediaPermalink`, `getPublishingLimit`, `getMediaInsights`, `refreshToken` | Instagram — Content Publishing container flow (create, poll, publish, permalink) plus media insights. |
|
|
19
20
|
| Instantly | `createInstantlyAdapter(credential)` | `sendReply`, `removeFromSubsequence`, `getEmails`, `updateInterestStatus`, `addToCampaign`, `listCampaigns`, `getCampaign`, `updateCampaign`, `pauseCampaign`, `activateCampaign`, `getCampaignAnalytics`, `getStepAnalytics`, `bulkAddLeads`, `getAccountHealth`, `createInboxTest`, `createCampaign`, `getDailyCampaignAnalytics`, `listLeads`, `bulkDeleteLeads`, `deleteCampaign`, `patchLead` | Instantly — manage email outreach campaigns, leads, analytics, and inbox health. |
|
|
20
21
|
| MillionVerifier | `createMillionVerifierAdapter(credential)` | `verifyEmail`, `checkCredits` | MillionVerifier — verify email deliverability and check account credits. |
|
|
21
22
|
| Anymailfinder | `createAnymailfinderAdapter(credential)` | `findCompanyEmail`, `findPersonEmail`, `findDecisionMakerEmail`, `verifyEmail` | Anymailfinder — find and verify company and person email addresses. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Platform Adapters"
|
|
3
|
-
description: "Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker
|
|
3
|
+
description: "Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the PLATFORM_EXPORTS list in the generator, checked against the adapter directory on every run."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
{/* @generated by .claude/_gen/sync-sdk-adapters.ts — DO NOT EDIT */}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Platform Tools
|
|
3
|
-
description: Access
|
|
3
|
+
description: Access 28 adapters (14 integration + 14 platform) from your SDK workflows -- typed adapters, credential security model, and working code examples
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Your SDK workflows have access to
|
|
6
|
+
Your SDK workflows have access to 28 adapters (14 integration + 14 platform) -- Gmail, Stripe, Google Sheets, PDF generation, human-in-the-loop approvals, storage, scheduling, and more. Credentials are managed server-side and never appear in your code.
|
|
7
7
|
|
|
8
8
|
**Typed adapters** are the recommended way to call tools. They provide full TypeScript autocomplete, compile-time method checking, and eliminate boilerplate. Use `platform.call()` only for tools that don't have an adapter yet.
|
|
9
9
|
|
|
@@ -43,7 +43,7 @@ Both patterns return a Promise that resolves with the tool result or rejects wit
|
|
|
43
43
|
|
|
44
44
|
## Integration Adapters
|
|
45
45
|
|
|
46
|
-
The SDK ships
|
|
46
|
+
The SDK ships 14 integration adapters (credential-bound factory functions) covering third-party APIs -- Attio, Apify, ClickUp, Dropbox, Gmail, Google Sheets, Instagram, Instantly, MillionVerifier, Anymailfinder, Tomba, Resend, SignatureAPI, and Stripe. Pass the credential name once at adapter creation. Supabase is covered separately under [Database Access](#database-access) below.
|
|
47
47
|
|
|
48
48
|
For the full per-adapter method tables, credential shapes, and code examples, see [Integration Adapters](adapters-integration.mdx) -- generated from the adapter source so it never drifts.
|
|
49
49
|
|
|
@@ -130,9 +130,9 @@ Credentials are created in the command center UI: navigate to Credentials -> Add
|
|
|
130
130
|
|
|
131
131
|
## Platform Services
|
|
132
132
|
|
|
133
|
-
The SDK ships
|
|
133
|
+
The SDK ships 14 platform service singletons available without a `credential` field -- imported directly from `@elevasis/sdk/worker`: `scheduler`, `llm`, `storage`, `notifications`, `acqDb`, `projects`, `crm`, `list`, `pdf`, `approval`, `execution`, `email`, `artifacts`, and `content`. The platform injects context server-side, so no credential is passed.
|
|
134
134
|
|
|
135
|
-
For the full per-service method tables (including the `acqDb`
|
|
135
|
+
For the full per-service method tables (including the `acqDb` 60-method surface), see [Platform Adapters](adapters-platform.mdx) -- generated from the adapter source.
|
|
136
136
|
|
|
137
137
|
## LLM Tool
|
|
138
138
|
|
|
@@ -195,8 +195,8 @@ const qualified = await platform.call({
|
|
|
195
195
|
|
|
196
196
|
## Documentation
|
|
197
197
|
|
|
198
|
-
- [Integration Adapters](adapters-integration.mdx) - All
|
|
199
|
-
- [Platform Adapters](adapters-platform.mdx) - All
|
|
198
|
+
- [Integration Adapters](adapters-integration.mdx) - All 14 integration adapters with method tables and code examples
|
|
199
|
+
- [Platform Adapters](adapters-platform.mdx) - All 14 platform service adapters with method tables and code examples
|
|
200
200
|
- [Adapter Type Safety](type-safety.mdx) - Required fields, discriminated unions, and intentionally loose adapter types
|
|
201
201
|
|
|
202
202
|
---
|
|
@@ -325,14 +325,14 @@ const myAgent: AgentDefinition = {
|
|
|
325
325
|
|
|
326
326
|
### config (agent-specific fields)
|
|
327
327
|
|
|
328
|
-
| Field | Type | Description
|
|
329
|
-
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
330
|
-
| `kind` | `'orchestrator' | 'specialist' | 'utility' | 'platform'` | Required. What role this agent plays — not enforced at runtime today, but tenant-authored and validated at deploy against your OM resource descriptor's own `kind`.
|
|
331
|
-
| `systemPrompt` | `string` | Required. The agent's base system prompt.
|
|
332
|
-
| `constraints` | `{ maxIterations?, timeout?, maxSessionMemoryKeys?, maxMemoryTokens? }` (optional) | Iteration budget, execution timeout in ms, and session-memory limits.
|
|
333
|
-
| `sessionCapable` | `boolean` (optional) | Opt in to multi-turn sessions. Defaults to `false` — the shape used in the example above, which completes and returns `contract.outputSchema` in a single turn.
|
|
334
|
-
| `securityLevel` | `'standard' | 'hardened' | 'none'` (optional) | Prompt-hardening tier. Auto-derived from `sessionCapable` when omitted (`true` → `'hardened'`, `false` → `'standard'`).
|
|
335
|
-
| `memoryPreferences` | `string` (optional) | Guidance injected into the system prompt when session memory management is enabled.
|
|
328
|
+
| Field | Type | Description |
|
|
329
|
+
| ------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
330
|
+
| `kind` | `'orchestrator' | 'specialist' | 'utility' | 'platform'` | Required. What role this agent plays — not enforced at runtime today, but tenant-authored and validated at deploy against your OM resource descriptor's own `kind`. |
|
|
331
|
+
| `systemPrompt` | `string` | Required. The agent's base system prompt. |
|
|
332
|
+
| `constraints` | `{ maxIterations?, timeout?, maxSessionMemoryKeys?, maxMemoryTokens? }` (optional) | Iteration budget, execution timeout in ms, and session-memory limits. |
|
|
333
|
+
| `sessionCapable` | `boolean` (optional) | Opt in to multi-turn sessions. Defaults to `false` — the shape used in the example above, which completes and returns `contract.outputSchema` in a single turn. |
|
|
334
|
+
| `securityLevel` | `'standard' | 'hardened' | 'none'` (optional) | Prompt-hardening tier. Auto-derived from `sessionCapable` when omitted (`true` → `'hardened'`, `false` → `'standard'`). `'none'` disables prompt hardening. It is a deliberate explicit opt-in, valid even for a session-capable agent when that agent's surface has no untrusted-input boundary to defend. |
|
|
335
|
+
| `memoryPreferences` | `string` (optional) | Guidance injected into the system prompt when session memory management is enabled. |
|
|
336
336
|
|
|
337
337
|
### contract (agent)
|
|
338
338
|
|