Skip to content
Merged
5 changes: 3 additions & 2 deletions schemas/policy-preset.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"$defs": {
"networkPolicyEntry": {
"type": "object",
"required": ["name", "endpoints"],
"required": ["name", "endpoints", "binaries"],
"properties": {
"name": { "type": "string" },
"endpoints": {
Expand All @@ -37,7 +37,8 @@
},
"binaries": {
"type": "array",
"items": { "$ref": "#/$defs/binary" }
"items": { "$ref": "#/$defs/binary" },
"minItems": 1
}
}
},
Expand Down
48 changes: 48 additions & 0 deletions schemas/router-pool-config.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"$comment": "SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\nSPDX-License-Identifier: Apache-2.0",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/NVIDIA/NemoClaw/schemas/router-pool-config.schema.json",
"title": "NemoClaw Model Router Pool Config",
"description": "Schema for nemoclaw-blueprint/router/pool-config.yaml.",
"type": "object",
"required": ["routing", "models"],
"additionalProperties": false,
"properties": {
"routing": {
"type": "object",
"required": ["method", "checkpoint", "tolerance", "encoder", "encoder_backend"],
"additionalProperties": false,
"properties": {
"method": { "type": "string", "minLength": 1 },
"checkpoint": { "type": "string", "minLength": 1 },
"tolerance": { "type": "number", "minimum": 0, "maximum": 1 },
"encoder": { "type": "string", "minLength": 1 },
"encoder_backend": { "type": "string", "minLength": 1 }
}
},
"models": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"name",
"display_name",
"litellm_model",
"cost_per_m_input_tokens",
"cost_per_m_output_tokens",
"api_base"
],
"additionalProperties": false,
"properties": {
"name": { "type": "string", "minLength": 1 },
"display_name": { "type": "string", "minLength": 1 },
"litellm_model": { "type": "string", "minLength": 1 },
"cost_per_m_input_tokens": { "type": "number", "minimum": 0 },
"cost_per_m_output_tokens": { "type": "number", "minimum": 0 },
"api_base": { "type": "string", "pattern": "^https://" }
}
}
}
}
}
5 changes: 3 additions & 2 deletions schemas/sandbox-policy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"$defs": {
"networkPolicyEntry": {
"type": "object",
"required": ["name", "endpoints"],
"required": ["name", "endpoints", "binaries"],
"properties": {
"name": { "type": "string" },
"endpoints": {
Expand All @@ -62,7 +62,8 @@
},
"binaries": {
"type": "array",
"items": { "$ref": "#/$defs/binary" }
"items": { "$ref": "#/$defs/binary" },
"minItems": 1
}
}
},
Expand Down
52 changes: 52 additions & 0 deletions scripts/checks/layer-import-boundaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ function isCommandFile(repoPath: string): boolean {
return repoPath.startsWith("src/commands/");
}

function isMessagingManifestFile(repoPath: string): boolean {
return repoPath.startsWith("src/lib/messaging/manifest/");
}

function isActionFile(repoPath: string): boolean {
if (repoPath.startsWith("src/lib/actions/")) return true;
return /(^|\/)[^/]+-actions?\.ts$/.test(repoPath);
Expand Down Expand Up @@ -262,6 +266,51 @@ function checkNoBinLibShimImport(absPath: string, repoPath: string, violations:
}
}

function checkMessagingManifestFile(
absPath: string,
repoPath: string,
violations: Violation[],
): void {
const forbiddenFragments = [
"gateway",
"state/registry",
"credentials",
"node:fs",
"node:child_process",
"child_process",
"adapters/openshell",
"src/commands",
"lib/actions",
];

for (const ref of collectImportRefs(absPath)) {
if (ref.specifier === "fs" || ref.specifier.startsWith("fs/")) {
addViolation(
violations,
repoPath,
ref.line,
ref.column,
"messaging-manifest-purity",
"messaging manifest modules must not import fs",
);
continue;
}
const target = resolveInternalImport(absPath, ref.specifier);
const haystack = `${ref.specifier}\n${target ?? ""}`;
const fragment = forbiddenFragments.find((candidate) => haystack.includes(candidate));
if (fragment) {
addViolation(
violations,
repoPath,
ref.line,
ref.column,
"messaging-manifest-purity",
`messaging manifest modules must not import ${fragment}`,
);
}
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

function checkCommandFile(absPath: string, repoPath: string, violations: Violation[]): void {
const sourceFile = sourceFileFor(absPath);
let commandClassCount = 0;
Expand Down Expand Up @@ -305,6 +354,9 @@ export function findLayerImportBoundaryViolations(root = SRC_ROOT): Violation[]
if (isDomainFile(repoPath)) checkDomainFile(absPath, repoPath, violations);
if (isActionFile(repoPath)) checkActionFile(absPath, repoPath, violations);
if (isAdapterFile(repoPath)) checkAdapterFile(absPath, repoPath, violations);
if (isMessagingManifestFile(repoPath)) {
checkMessagingManifestFile(absPath, repoPath, violations);
}
if (isCommandFile(repoPath)) checkCommandFile(absPath, repoPath, violations);
}
return violations;
Expand Down
Loading
Loading