@neuralis/brain-core 0.3.1 → 0.4.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/README.md +88 -1417
- package/app/README.md +4 -4
- package/app/cards/FilesystemCardShell.tsx +42 -4
- package/app/cards/FilesystemChangeCard.tsx +34 -11
- package/app/cards/README.md +6 -5
- package/app/cards/diffUtils.ts +99 -1
- package/app/filesystem/FilesystemHost.tsx +24 -2
- package/app/filesystem/README.md +1 -1
- package/app/filesystem/api/README.md +3 -3
- package/app/filesystem/api/index.ts +38 -14
- package/app/filesystem/api/projectPackages.ts +13 -102
- package/app/filesystem/domain/types.ts +30 -10
- package/app/filesystem/hooks/README.md +4 -4
- package/app/filesystem/hooks/useDiscoverableSources.ts +19 -30
- package/app/filesystem/hooks/useFilesystemSSE.ts +42 -2
- package/app/filesystem/host/README.md +6 -4
- package/app/filesystem/host/buildFilesystemHostValue.ts +28 -2
- package/app/filesystem/host/installFilesystemHostComponents.tsx +1 -1
- package/app/filesystem/lib/sourceKindForm.ts +210 -27
- package/app/filesystem/lib/treeVisualState.tsx +98 -4
- package/app/filesystem/store/README.md +1 -0
- package/app/filesystem/store/filesystemStore.ts +99 -8
- package/app/filesystem/store/gitSlice.ts +5 -0
- package/app/filesystem/store/helpers.ts +17 -0
- package/app/filesystem/store/listSlice.ts +8 -0
- package/app/filesystem/ui/CodeEditor.tsx +18 -3
- package/app/filesystem/ui/DiscoverDock.tsx +5 -1
- package/app/filesystem/ui/FileEditor.tsx +15 -10
- package/app/filesystem/ui/FileTree.tsx +75 -24
- package/app/filesystem/ui/FilesystemWidget.tsx +10 -2
- package/app/filesystem/ui/FolderPicker.tsx +251 -0
- package/app/filesystem/ui/GitControlPanel.tsx +7 -2
- package/app/filesystem/ui/PackagesPanel.tsx +52 -374
- package/app/filesystem/ui/PendingChangesPanel.tsx +1 -1
- package/app/filesystem/ui/PolicyEditor.tsx +109 -24
- package/app/filesystem/ui/README.md +30 -23
- package/app/filesystem/ui/RawMediaPreview.tsx +58 -0
- package/app/filesystem/ui/SourceBranchHeader.tsx +4 -4
- package/app/filesystem/ui/SourcesPanel.tsx +502 -342
- package/app/filesystem/ui/Toolbar.tsx +1 -2
- package/app/filesystem/ui/VectorHealthPanel.tsx +2 -2
- package/app/shared/filesystem.png +0 -0
- package/dist/app/host.js +58 -46
- package/dist/scripts/sourceRootPairV1.d.ts +47 -0
- package/dist/scripts/sourceRootPairV1.d.ts.map +1 -0
- package/dist/scripts/sourceRootPairV1.js +147 -0
- package/dist/scripts/sourceRootPairV1.js.map +1 -0
- package/dist/scripts/sourceToFolderV1.d.ts +56 -0
- package/dist/scripts/sourceToFolderV1.d.ts.map +1 -0
- package/dist/scripts/sourceToFolderV1.js +152 -0
- package/dist/scripts/sourceToFolderV1.js.map +1 -0
- package/dist/scripts/sourceToHostV1.d.ts +56 -0
- package/dist/scripts/sourceToHostV1.d.ts.map +1 -0
- package/dist/scripts/sourceToHostV1.js +132 -0
- package/dist/scripts/sourceToHostV1.js.map +1 -0
- package/dist/src/channels/filesystem.d.ts +1 -1
- package/dist/src/channels/filesystem.js +1 -1
- package/dist/src/connectors/AppSourceConfigStore.d.ts +17 -3
- package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
- package/dist/src/connectors/AppSourceConfigStore.js +46 -6
- package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
- package/dist/src/connectors/HostConnector.d.ts +201 -0
- package/dist/src/connectors/HostConnector.d.ts.map +1 -0
- package/dist/src/connectors/HostConnector.js +903 -0
- package/dist/src/connectors/HostConnector.js.map +1 -0
- package/dist/src/connectors/inProcessTransport.d.ts +131 -0
- package/dist/src/connectors/inProcessTransport.d.ts.map +1 -0
- package/dist/src/connectors/inProcessTransport.js +447 -0
- package/dist/src/connectors/inProcessTransport.js.map +1 -0
- package/dist/src/domain/access/callerPermissions.d.ts +29 -0
- package/dist/src/domain/access/callerPermissions.d.ts.map +1 -1
- package/dist/src/domain/access/callerPermissions.js +85 -5
- package/dist/src/domain/access/callerPermissions.js.map +1 -1
- package/dist/src/domain/access/nativeLocalFence.d.ts +65 -0
- package/dist/src/domain/access/nativeLocalFence.d.ts.map +1 -0
- package/dist/src/domain/access/nativeLocalFence.js +171 -0
- package/dist/src/domain/access/nativeLocalFence.js.map +1 -0
- package/dist/src/domain/access/uriPermission.js +3 -3
- package/dist/src/domain/access/uriPermission.js.map +1 -1
- package/dist/src/domain/byteRange.d.ts +15 -0
- package/dist/src/domain/byteRange.d.ts.map +1 -0
- package/dist/src/domain/byteRange.js +30 -0
- package/dist/src/domain/byteRange.js.map +1 -0
- package/dist/src/domain/defaultPermissions.d.ts.map +1 -1
- package/dist/src/domain/defaultPermissions.js +29 -0
- package/dist/src/domain/defaultPermissions.js.map +1 -1
- package/dist/src/domain/mime.d.ts +11 -19
- package/dist/src/domain/mime.d.ts.map +1 -1
- package/dist/src/domain/mime.js +13 -102
- package/dist/src/domain/mime.js.map +1 -1
- package/dist/src/domain/paths.d.ts.map +1 -1
- package/dist/src/domain/paths.js +5 -3
- package/dist/src/domain/paths.js.map +1 -1
- package/dist/src/domain/scopeAccessCtx.d.ts +2 -2
- package/dist/src/domain/scopeAccessCtx.js +2 -2
- package/dist/src/domain/sourceConfig.d.ts +52 -19
- package/dist/src/domain/sourceConfig.d.ts.map +1 -1
- package/dist/src/domain/sourceConfig.js +103 -19
- package/dist/src/domain/sourceConfig.js.map +1 -1
- package/dist/src/domain/sourcePackages.d.ts +8 -8
- package/dist/src/domain/sourcePackages.d.ts.map +1 -1
- package/dist/src/domain/sourceRootPair.d.ts +88 -0
- package/dist/src/domain/sourceRootPair.d.ts.map +1 -0
- package/dist/src/domain/sourceRootPair.js +108 -0
- package/dist/src/domain/sourceRootPair.js.map +1 -0
- package/dist/src/domain/syncTypes.d.ts +8 -1
- package/dist/src/domain/syncTypes.d.ts.map +1 -1
- package/dist/src/domain/syncTypes.js +1 -0
- package/dist/src/domain/syncTypes.js.map +1 -1
- package/dist/src/domain/types.d.ts +32 -2
- package/dist/src/domain/types.d.ts.map +1 -1
- package/dist/src/domain/uri.d.ts.map +1 -1
- package/dist/src/domain/uri.js +3 -2
- package/dist/src/domain/uri.js.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.js +2 -5
- package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.js +2 -3
- package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.d.ts +2 -0
- package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.js +10 -2
- package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.d.ts +2 -0
- package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.js +8 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
- package/dist/src/embeddings/factory.d.ts +5 -3
- package/dist/src/embeddings/factory.d.ts.map +1 -1
- package/dist/src/embeddings/factory.js +7 -3
- package/dist/src/embeddings/factory.js.map +1 -1
- package/dist/src/embeddings/models.d.ts +1 -1
- package/dist/src/embeddings/models.d.ts.map +1 -1
- package/dist/src/embeddings/retry.js +1 -1
- package/dist/src/embeddings/retry.js.map +1 -1
- package/dist/src/embeddings/types.d.ts +6 -0
- package/dist/src/embeddings/types.d.ts.map +1 -1
- package/dist/src/embeddings/types.js +11 -0
- package/dist/src/embeddings/types.js.map +1 -1
- package/dist/src/events/pending.d.ts +1 -1
- package/dist/src/events/pending.js +1 -1
- package/dist/src/git/GitRunner.d.ts +110 -30
- package/dist/src/git/GitRunner.d.ts.map +1 -1
- package/dist/src/git/GitRunner.js +511 -199
- package/dist/src/git/GitRunner.js.map +1 -1
- package/dist/src/git/GitWatchRegistry.d.ts +41 -35
- package/dist/src/git/GitWatchRegistry.d.ts.map +1 -1
- package/dist/src/git/GitWatchRegistry.js +61 -79
- package/dist/src/git/GitWatchRegistry.js.map +1 -1
- package/dist/src/git/gitPlace.d.ts +61 -0
- package/dist/src/git/gitPlace.d.ts.map +1 -0
- package/dist/src/git/gitPlace.js +74 -0
- package/dist/src/git/gitPlace.js.map +1 -0
- package/dist/src/git/sourceGitControl.d.ts +33 -21
- package/dist/src/git/sourceGitControl.d.ts.map +1 -1
- package/dist/src/git/sourceGitControl.js +211 -95
- package/dist/src/git/sourceGitControl.js.map +1 -1
- package/dist/src/git/sourceGitStatus.js +1 -1
- package/dist/src/git/sourceGitStatus.js.map +1 -1
- package/dist/src/git/untrackedStats.js +1 -1
- package/dist/src/git/untrackedStats.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lifecycle.d.ts +9 -12
- package/dist/src/lifecycle.d.ts.map +1 -1
- package/dist/src/lifecycle.js +2 -1
- package/dist/src/lifecycle.js.map +1 -1
- package/dist/src/routes/approve.d.ts +1 -1
- package/dist/src/routes/approve.js +1 -1
- package/dist/src/routes/events.d.ts +1 -1
- package/dist/src/routes/events.js +1 -1
- package/dist/src/routes/git.d.ts +7 -7
- package/dist/src/routes/git.d.ts.map +1 -1
- package/dist/src/routes/git.js +201 -72
- package/dist/src/routes/git.js.map +1 -1
- package/dist/src/routes/health.d.ts +6 -6
- package/dist/src/routes/health.js +12 -12
- package/dist/src/routes/helpers/sourceNotConfigured.d.ts +1 -1
- package/dist/src/routes/helpers/sourceNotConfigured.js +1 -1
- package/dist/src/routes/helpers/uriGuard.d.ts +1 -1
- package/dist/src/routes/helpers/uriGuard.d.ts.map +1 -1
- package/dist/src/routes/helpers/uriGuard.js +3 -2
- package/dist/src/routes/helpers/uriGuard.js.map +1 -1
- package/dist/src/routes/helpers.d.ts +11 -4
- package/dist/src/routes/helpers.d.ts.map +1 -1
- package/dist/src/routes/helpers.js +13 -6
- package/dist/src/routes/helpers.js.map +1 -1
- package/dist/src/routes/list.d.ts +1 -1
- package/dist/src/routes/list.d.ts.map +1 -1
- package/dist/src/routes/list.js +3 -4
- package/dist/src/routes/list.js.map +1 -1
- package/dist/src/routes/pending.d.ts +4 -4
- package/dist/src/routes/pending.js +9 -9
- package/dist/src/routes/policies.d.ts +10 -8
- package/dist/src/routes/policies.d.ts.map +1 -1
- package/dist/src/routes/policies.js +31 -25
- package/dist/src/routes/policies.js.map +1 -1
- package/dist/src/routes/raw.d.ts +1 -1
- package/dist/src/routes/raw.d.ts.map +1 -1
- package/dist/src/routes/raw.js +66 -12
- package/dist/src/routes/raw.js.map +1 -1
- package/dist/src/routes/read.d.ts +1 -1
- package/dist/src/routes/read.js +1 -1
- package/dist/src/routes/search.d.ts +1 -1
- package/dist/src/routes/search.js +1 -1
- package/dist/src/routes/sources.d.ts +63 -6
- package/dist/src/routes/sources.d.ts.map +1 -1
- package/dist/src/routes/sources.js +494 -382
- package/dist/src/routes/sources.js.map +1 -1
- package/dist/src/routes/upload.d.ts +1 -1
- package/dist/src/routes/upload.js +1 -1
- package/dist/src/routes/write.d.ts +2 -2
- package/dist/src/routes/write.js +2 -2
- package/dist/src/services/BridgeService.d.ts +21 -35
- package/dist/src/services/BridgeService.d.ts.map +1 -1
- package/dist/src/services/BridgeService.js +42 -88
- package/dist/src/services/BridgeService.js.map +1 -1
- package/dist/src/services/FilesystemService.d.ts +4 -3
- package/dist/src/services/FilesystemService.d.ts.map +1 -1
- package/dist/src/services/FilesystemService.js +112 -34
- package/dist/src/services/FilesystemService.js.map +1 -1
- package/dist/src/services/FilesystemUiService.d.ts +4 -1
- package/dist/src/services/FilesystemUiService.d.ts.map +1 -1
- package/dist/src/services/FilesystemUiService.js +66 -25
- package/dist/src/services/FilesystemUiService.js.map +1 -1
- package/dist/src/services/SyncScheduler.d.ts +12 -4
- package/dist/src/services/SyncScheduler.d.ts.map +1 -1
- package/dist/src/services/SyncScheduler.js +37 -8
- package/dist/src/services/SyncScheduler.js.map +1 -1
- package/dist/src/services/baselineRepair.d.ts +13 -3
- package/dist/src/services/baselineRepair.d.ts.map +1 -1
- package/dist/src/services/baselineRepair.js +13 -3
- package/dist/src/services/baselineRepair.js.map +1 -1
- package/dist/src/services/declaredSources.d.ts +132 -43
- package/dist/src/services/declaredSources.d.ts.map +1 -1
- package/dist/src/services/declaredSources.js +118 -45
- package/dist/src/services/declaredSources.js.map +1 -1
- package/dist/src/store/dataFormats.d.ts +17 -2
- package/dist/src/store/dataFormats.d.ts.map +1 -1
- package/dist/src/store/dataFormats.js +18 -3
- package/dist/src/store/dataFormats.js.map +1 -1
- package/dist/src/sync/DeltaSyncRunner.d.ts.map +1 -1
- package/dist/src/sync/DeltaSyncRunner.js +144 -4
- package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
- package/dist/src/sync/SyncJobQueue.d.ts +7 -2
- package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
- package/dist/src/sync/SyncJobQueue.js +16 -10
- package/dist/src/sync/SyncJobQueue.js.map +1 -1
- package/dist/src/sync/SyncWatchService.d.ts +21 -4
- package/dist/src/sync/SyncWatchService.d.ts.map +1 -1
- package/dist/src/sync/SyncWatchService.js +115 -10
- package/dist/src/sync/SyncWatchService.js.map +1 -1
- package/dist/src/sync/categoryInference.d.ts +1 -1
- package/dist/src/sync/categoryInference.js +1 -1
- package/dist/src/tools/execCtx.d.ts +2 -2
- package/dist/src/tools/execCtx.js +2 -2
- package/dist/src/tools/fs_read.d.ts.map +1 -1
- package/dist/src/tools/fs_read.js +5 -0
- package/dist/src/tools/fs_read.js.map +1 -1
- package/dist/src/usecases/admitSourceRoot.d.ts +65 -0
- package/dist/src/usecases/admitSourceRoot.d.ts.map +1 -0
- package/dist/src/usecases/admitSourceRoot.js +85 -0
- package/dist/src/usecases/admitSourceRoot.js.map +1 -0
- package/dist/src/usecases/browseSourceFolders.d.ts +85 -0
- package/dist/src/usecases/browseSourceFolders.d.ts.map +1 -0
- package/dist/src/usecases/browseSourceFolders.js +210 -0
- package/dist/src/usecases/browseSourceFolders.js.map +1 -0
- package/dist/src/usecases/createDeclaredSources.d.ts +13 -2
- package/dist/src/usecases/createDeclaredSources.d.ts.map +1 -1
- package/dist/src/usecases/createDeclaredSources.js +39 -0
- package/dist/src/usecases/createDeclaredSources.js.map +1 -1
- package/dist/src/usecases/embeddingBacklog.js +1 -1
- package/dist/src/usecases/embeddingBacklog.js.map +1 -1
- package/dist/src/usecases/list.d.ts.map +1 -1
- package/dist/src/usecases/list.js +83 -26
- package/dist/src/usecases/list.js.map +1 -1
- package/dist/src/usecases/listAttachableDevices.d.ts +13 -0
- package/dist/src/usecases/listAttachableDevices.d.ts.map +1 -0
- package/dist/src/usecases/listAttachableDevices.js +10 -0
- package/dist/src/usecases/listAttachableDevices.js.map +1 -0
- package/dist/src/usecases/listSourcePackages.d.ts.map +1 -1
- package/dist/src/usecases/listSourcePackages.js +2 -5
- package/dist/src/usecases/listSourcePackages.js.map +1 -1
- package/dist/src/usecases/purgeExcludedPoints.d.ts.map +1 -1
- package/dist/src/usecases/purgeExcludedPoints.js +3 -2
- package/dist/src/usecases/purgeExcludedPoints.js.map +1 -1
- package/dist/src/usecases/readFiles.d.ts.map +1 -1
- package/dist/src/usecases/readFiles.js +99 -1
- package/dist/src/usecases/readFiles.js.map +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.js +2 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -1
- package/dist/src/usecases/revokePrincipal.d.ts +7 -5
- package/dist/src/usecases/revokePrincipal.d.ts.map +1 -1
- package/dist/src/usecases/revokePrincipal.js +29 -7
- package/dist/src/usecases/revokePrincipal.js.map +1 -1
- package/dist/src/usecases/scheduleSourceSync.d.ts +7 -0
- package/dist/src/usecases/scheduleSourceSync.d.ts.map +1 -1
- package/dist/src/usecases/scheduleSourceSync.js +6 -5
- package/dist/src/usecases/scheduleSourceSync.js.map +1 -1
- package/dist/src/usecases/syncPointWrites.d.ts +2 -0
- package/dist/src/usecases/syncPointWrites.d.ts.map +1 -1
- package/dist/src/usecases/syncPointWrites.js +5 -1
- package/dist/src/usecases/syncPointWrites.js.map +1 -1
- package/dist/src/usecases/triggerSourceSync.d.ts +46 -0
- package/dist/src/usecases/triggerSourceSync.d.ts.map +1 -0
- package/dist/src/usecases/triggerSourceSync.js +75 -0
- package/dist/src/usecases/triggerSourceSync.js.map +1 -0
- package/dist/src/usecases/uploadBinary.d.ts +2 -1
- package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
- package/dist/src/usecases/uploadBinary.js +2 -2
- package/dist/src/usecases/uploadBinary.js.map +1 -1
- package/dist/src/usecases/vector/endpointGuard.d.ts +1 -1
- package/dist/src/usecases/vector/endpointGuard.js +1 -1
- package/dist/src/usecases/vectorMaintenance.js +1 -1
- package/dist/src/usecases/vectorMaintenance.js.map +1 -1
- package/dist/src/usecases/write/content.js +1 -1
- package/dist/src/vector/qdrantClient.d.ts +1 -1
- package/dist/src/vector/qdrantClient.js +1 -1
- package/dist/src/wiring.d.ts +3 -0
- package/dist/src/wiring.d.ts.map +1 -1
- package/dist/src/wiring.js +72 -6
- package/dist/src/wiring.js.map +1 -1
- package/dist/tools/fs_list.json +1 -1
- package/dist/tools/fs_read.json +1 -1
- package/dist/tools/fs_search.json +1 -1
- package/dist/tools/fs_write.json +1 -1
- package/instructions/brain-model.md +1 -1
- package/package.json +212 -114
- package/rules/brain-rules.md +2 -2
- package/skills/brain-start/SKILL.md +1 -1
- package/skills/connect-business-data/SKILL.md +3 -3
- package/skills/create-package/SKILL.md +26 -26
- package/skills/create-package/references/config-and-credentials.md +16 -13
- package/skills/create-package/references/connectors-and-uri-policies.md +39 -25
- package/skills/create-package/references/manifest-and-discovery.md +12 -12
- package/skills/create-package/references/runtime-and-build.md +19 -19
- package/skills/create-package/references/skills-and-context.md +36 -20
- package/skills/create-package/references/surfaces-and-design.md +16 -16
- package/skills/create-package/references/team-and-workflows.md +2 -2
- package/skills/create-package/references/test-and-ship.md +21 -21
- package/skills/create-package/references/tools-and-schemas.md +5 -5
- package/skills/create-package/scripts/{check-package.sh → check-package.mjs} +79 -65
- package/skills/create-package/scripts/{verify-loaded.sh → verify-loaded.mjs} +156 -162
- package/skills/git/SKILL.md +53 -51
- package/skills/manage-files/SKILL.md +22 -25
- package/skills/manage-sources/SKILL.md +128 -87
- package/skills/manage-uri-policy/SKILL.md +18 -15
- package/skills/organize/SKILL.md +1 -1
- package/skills/sync/SKILL.md +3 -3
- package/tools/fs_list.json +1 -1
- package/tools/fs_read.json +1 -1
- package/tools/fs_search.json +1 -1
- package/tools/fs_write.json +1 -1
- package/workflows/sources-digest.json +1 -1
- package/dist/src/connectors/LocalDiskConnector.d.ts +0 -171
- package/dist/src/connectors/LocalDiskConnector.d.ts.map +0 -1
- package/dist/src/connectors/LocalDiskConnector.js +0 -1233
- package/dist/src/connectors/LocalDiskConnector.js.map +0 -1
- package/docs/drive-overview.md +0 -59
- package/skills/manage-files/scripts/copy.sh +0 -7
- package/skills/manage-files/scripts/create.sh +0 -7
- package/skills/manage-files/scripts/mkdir.sh +0 -7
- package/skills/manage-files/scripts/modify.sh +0 -7
- package/skills/manage-files/scripts/upload.sh +0 -16
- package/skills/manage-files/scripts/write.sh +0 -29
- package/skills/manage-sources/scripts/reembed.sh +0 -23
package/rules/brain-rules.md
CHANGED
|
@@ -16,7 +16,7 @@ activation:
|
|
|
16
16
|
3b. **The ladder, once:** `fs_list` = the SHAPE of a place you can name · `fs_search` = FINDING one you cannot · `fs_read` = the CONTENT once you can · `execute` = when you need a PROGRAM, never because you skipped the three. `<runtime_stack>` `data_areas` names where each package keeps its files; start there.
|
|
17
17
|
4. **Presence and index state differ.** `unindexed` content is live but not semantically searchable; `stale_indexed` stays indexed after its connector entry disappeared **or after the connector failed to answer** — neither proves a file is gone.
|
|
18
18
|
|
|
19
|
-
Tool descriptions own the choice among list/search/read/write; follow their discovery and recovery hints.
|
|
19
|
+
Tool descriptions own the choice among list/search/read/write; follow their discovery and recovery hints. `<runtime_stack>` names the live sources and their schemes; the model itself is in the on-demand `brain-model` (read it via `files/content`).
|
|
20
20
|
|
|
21
21
|
## Writes
|
|
22
22
|
|
|
@@ -28,7 +28,7 @@ Tool descriptions own the choice among list/search/read/write; follow their disc
|
|
|
28
28
|
|
|
29
29
|
## Security floor
|
|
30
30
|
|
|
31
|
-
10. **Paths are policy-gated.** Every URI is checked for read/write/exec; uncovered paths deny by default, shell included. Never build an alternate path to evade policy. `manage-uri-policy` is the way to a narrower exception: reading one needs `
|
|
31
|
+
10. **Paths are policy-gated.** Every URI is checked for read/write/exec; uncovered paths deny by default, shell included. Never build an alternate path to evade policy. `manage-uri-policy` is the way to a narrower exception: reading one needs `files.read`, changing one escalates to `sources.policy` — no grant below `admin`.
|
|
32
32
|
11. **Scope is enforced.** Files are scoped by user, project and agent; another identity's subtree is not yours, and routes reject cross-scope access.
|
|
33
33
|
12. **Source state is three-valued.** No config → `source_not_configured`, and the reply lists the sources you CAN address, so pick one instead of retrying. Configured but off → `source_disabled`, whatever the policy allows. On → policy decides. **Which one you SEE depends on the call:** a schemed name hits the path gate first, and a read reports per file inside a success. Check `<workspace_live>` before diagnosing absence.
|
|
34
34
|
13. **Host paths are optional.** A source may have no `os_uri`: address it by URI, never a made-up OS path.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
requiredFeatures: [
|
|
2
|
+
requiredFeatures: [files.read]
|
|
3
3
|
name: brain-start
|
|
4
4
|
description: "Survey an unfamiliar workspace and recommend evidence-based next steps: inspect live sources, index health, packages, and useful existing material before creating anything. Use for “what is here or where should we start?” requests, not as a substitute for executing a specific task."
|
|
5
5
|
allowed-tools: fs_search fs_list fs_read
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
requiredFeatures: [
|
|
2
|
+
requiredFeatures: [files.read]
|
|
3
3
|
name: connect-business-data
|
|
4
4
|
description: "Connect governed organisation or personal data — files, exports, records, APIs, databases, MCP services — deciding ownership, storage, scope, policy, retention and copy permission first. Use before real business-data work; sync/index the source and build capabilities around it without copying datasets into identity or memory."
|
|
5
5
|
allowed-tools: execute, connect
|
|
@@ -40,7 +40,7 @@ retention and indexing behavior.
|
|
|
40
40
|
vendor's official skill, MCP server or plugin (create-package
|
|
41
41
|
`references/connectors-and-uri-policies.md` §The headline); build a source connector only when
|
|
42
42
|
neither exists or searchable filesystem semantics are required. An outbound connector belongs
|
|
43
|
-
to ONE tenant — the platform lane for a
|
|
43
|
+
to ONE tenant — the platform lane for a native install, otherwise the owning project — so
|
|
44
44
|
the set you can see is the platform lane plus your own project, and an id from another project
|
|
45
45
|
answers the same generic `404` as a typo. Its write surface is admin-gated: listing rides
|
|
46
46
|
`core.observe`, but creating, configuring, connecting, enabling or deleting one needs
|
|
@@ -55,7 +55,7 @@ retention and indexing behavior.
|
|
|
55
55
|
|
|
56
56
|
Use `connect` to list sources, inspect one source's health, or create a source
|
|
57
57
|
from its explicit `{connection, permissions, sync?, description?, scope?,
|
|
58
|
-
|
|
58
|
+
packageFolders?}` options. Use `manage-sources` for the full lifecycle,
|
|
59
59
|
including kind/schema discovery, policy-preserving updates, sync and deletion:
|
|
60
60
|
|
|
61
61
|
1. List source kinds and read the chosen kind's schema.
|
|
@@ -31,10 +31,10 @@ a human can press is half a capability.
|
|
|
31
31
|
|
|
32
32
|
1. **Prove it does not already exist.** Mandatory, not advisory: a second skill that half-duplicates an existing one is worse than none — both match, and the model picks between them at random.
|
|
33
33
|
2. **Fix before you add.** Extend the existing skill, tool or reference; a new file needs a stated reason the existing owner cannot hold it. An edit leaves the file no larger unless it says why — improve the sentence that is now wrong, never append a changelog or a "we used to think" note.
|
|
34
|
-
3. **Category comes from the folder, never from frontmatter** — `skills/<name>/SKILL.md`, and flat `.md` under `rules/`, `instructions/`, `agents/`, `docs/`. A `category:` or `role:` key is ignored. And every `.md` in ALL FOUR flat categories needs `id:` or `name:` frontmatter
|
|
35
|
-
4. **`requiredFeatures: [a, b]` is flat.**
|
|
34
|
+
3. **Category comes from the folder, never from frontmatter** — `skills/<name>/SKILL.md`, and flat `.md` under `rules/`, `instructions/`, `agents/`, `docs/`. A `category:` or `role:` key is ignored. And every `.md` in ALL FOUR flat categories needs a non-empty `id:` or `name:` frontmatter or discovery silently skips it — ONE kernel rule (`admitsContribution`) that runs the same on an installed package, a `_packages/` drop, a synced source (there it is indexed as a plain `file`) and the marketplace scanner. Exempt are only the forms whose FILENAME is the identity: `skills/<name>/SKILL.md` (id from the folder name), `commands/*.md`, the identity basenames (`AGENTS.md`/`AGENTS.local.md`/`AGENT.md`, `CLAUDE.md`/`CLAUDE.local.md`, `GEMINI.md`, `.github/copilot-instructions.md`), `.cursorrules`/`.windsurfrules` and `.cursor/rules/*.mdc`. `*.agent.md` is NOT exempt.
|
|
35
|
+
4. **`requiredFeatures: [a, b]` is flat.** A nested `requires:` block is read by nothing, so your gate silently does not exist.
|
|
36
36
|
5. **Hidden means absent.** A caller lacking a feature never sees the skill, tool or widget, and activating it returns the same generic "not found" as a typo. Never build a "locked" state.
|
|
37
|
-
6. **Trust is assigned by where the package came from, never declared by it.** `access.trust: "
|
|
37
|
+
6. **Trust is assigned by where the package came from, never declared by it.** `access.trust: "native"` in a dropped manifest changes nothing.
|
|
38
38
|
7. **`package.json#files` must list every first-level runtime folder** (`dist`, `tools`, `workflows`, `skills`, `rules`, `instructions`, `agents`, `docs`, `team`, `hooks.json`, `app`). Omit one and it works locally and ships empty.
|
|
39
39
|
8. **A tool's name is its filename; the model-visible description is the root `description` field.** A tool file with no root `description` reaches the model with none.
|
|
40
40
|
9. **A widget needs a companion `kind: "dock"` surface.** A `dock:` block inside a widget is inert; without the companion the widget is unreachable and nothing warns.
|
|
@@ -67,10 +67,10 @@ system — a governed tool plus a skill teaching the craft of driving it.
|
|
|
67
67
|
|
|
68
68
|
### Surfaces: two renderers, one entry rule
|
|
69
69
|
|
|
70
|
-
**`direct`** is compiled React that the package's own
|
|
70
|
+
**`direct`** is compiled React that the package's own native host entrypoint registers — the
|
|
71
71
|
host never imports package TSX, so a `direct` surface renders only once that entrypoint is
|
|
72
72
|
installed at runtime from the prebuilt module the manifest's `app.module` names
|
|
73
|
-
(`neuralis-build ui`,
|
|
73
|
+
(`neuralis-build ui`, native only).
|
|
74
74
|
**`iframe`** is every other path and the only one a dropped package has. Nothing else exists:
|
|
75
75
|
`inline-html` and `wasm-ui` were removed and now fail validation with a migration message. WASM is
|
|
76
76
|
a **tool** runtime; there is no WASM UI engine.
|
|
@@ -112,7 +112,7 @@ what your package may contain.
|
|
|
112
112
|
|---|---|---|---|
|
|
113
113
|
| Lives in | a host dependency → `node_modules/@scope/name` | `<project>/_packages/<id>/` | a folder in a synced source, in a recognised layout |
|
|
114
114
|
| Who ships it | whoever controls the deploy config — **the dependency IS the trust act** | anyone who can write `_packages/` | anyone who can write the source |
|
|
115
|
-
| Trust |
|
|
115
|
+
| Trust | native (host-assigned) | untrusted; an admin may elevate to trusted; **never** native | inherits the source's scope and policy |
|
|
116
116
|
| Install step | add the dependency, restart | drop the folder (rescanned in ~half a second) | **none** — but it must be INDEXED to exist (below); once indexed it shows on the next stream |
|
|
117
117
|
| Manifest | `package.json#neuralis` | `package.json#neuralis` or `neuralis.package.json` | none — the folder layout IS the anchor |
|
|
118
118
|
| The five markdown categories | all five; rules inject | all five, but **rules become docs** and `prompt-context` activation is rewritten to `workspace` | all five, but **rules and identity files default OFF**, docs manual-only |
|
|
@@ -133,9 +133,9 @@ its own category, and none of them ships a skill, rule or agent you should follo
|
|
|
133
133
|
instruction.
|
|
134
134
|
|
|
135
135
|
**Column (a) has an operator loop, and it is not "restart".** An installed node package is brought
|
|
136
|
-
in by the person who controls the deploy configuration — registering the dependency, and,
|
|
136
|
+
in by the person who controls the deploy configuration — registering the dependency, and, in a Docker install where it
|
|
137
137
|
points at a folder being edited rather than a registry version, mounting that folder so the
|
|
138
|
-
container can see it.
|
|
138
|
+
container can see it. There the first install needs a real image rebuild; after that the package can be
|
|
139
139
|
rebuilt and swapped into the running container in about a minute instead of ten. Those commands are
|
|
140
140
|
not yours to run and not yours to document: the deployment ships its own operator runbook
|
|
141
141
|
(`neuralis-operations`) which owns them, including which form applies to how it was installed.
|
|
@@ -143,7 +143,7 @@ What IS yours: declare `files` correctly, because that whitelist decides what a
|
|
|
143
143
|
actually ships — see `references/manifest-and-discovery.md`. Columns (b) and (c) have no such loop;
|
|
144
144
|
a drop is rescanned in about half a second and source markdown needs no install at all.
|
|
145
145
|
|
|
146
|
-
**And a column-(a) package need not live in the host's tree at all.** A dependency can point at any directory on the deploying machine, so a package that is a product in its own right gets its own repository, its own history and its own release cadence, reached through a mount. Two things change when it does: the kernel packages become `peerDependencies` (the host already loads them — a hard dependency would give one contract two module graphs) with a relative `link:` devDependency so `tsc` still resolves, and your `tsconfig` has to inline what it used to extend. Four acts stay separate and none implies the next — git remote, mount, dependency registration, registry publish; only the third makes the package load. `references/runtime-and-build.md` §7b has the shape, including the two ways an
|
|
146
|
+
**And a column-(a) package need not live in the host's tree at all.** A dependency can point at any directory on the deploying machine, so a package that is a product in its own right gets its own repository, its own history and its own release cadence, reached through a mount in a Docker install. Two things change when it does: the kernel packages become `peerDependencies` (the host already loads them — a hard dependency would give one contract two module graphs) with a relative `link:` devDependency so `tsc` still resolves, and your `tsconfig` has to inline what it used to extend. Four acts stay separate and none implies the next — git remote, mount, dependency registration, registry publish; only the third makes the package load. `references/runtime-and-build.md` §7b has the shape, including the two ways an app-side gate fails while the package itself runs perfectly.
|
|
147
147
|
|
|
148
148
|
**Where your files go.** A drop: `fs_write({ uri: "packages://<dir>/package.json", create: { content } })` — that URI
|
|
149
149
|
is the project's `_packages/` folder, parent dirs made for you. The `packages://` path segment is
|
|
@@ -158,9 +158,9 @@ where you own them — improve those in place, never weakening a security rule y
|
|
|
158
158
|
|
|
159
159
|
**Address it.** A source slug is its own URI scheme, so a source package lives at `<slug>://<path>`:
|
|
160
160
|
a skill at `data://acme/skills/release-notes/SKILL.md` makes `data://acme` a package carrying one
|
|
161
|
-
skill, id `data://acme?project=<p>&scope=project`. Every project seeds two writable
|
|
161
|
+
skill, id `data://acme?project=<p>&scope=project`. Every project seeds two writable folder sources, `data://` and
|
|
162
162
|
`packages://`. Only the `<runtime_stack>` `sources` list has paths and permissions: `policy=` is your
|
|
163
|
-
own read/write/exec, `os_uri=` the host path, `container=` the shell's path — printed only when the
|
|
163
|
+
own read/write/exec, `os_uri=` the host path, `container=` the shell's path (on a native install the same as `os_uri`) — printed only when the
|
|
164
164
|
source has one; absent, cwd the URI itself (`cwd: "data://acme"`). `fs_list` with no `uri` gives
|
|
165
165
|
roots and index counts — no path, no policy. Write with `execute` (`action: "shell"`), not
|
|
166
166
|
`fs_write`: it stamps `category: "file"` and captures no frontmatter, and discovery keeps only the
|
|
@@ -179,8 +179,8 @@ ever is a contribution. The source needs no opt-in flag.
|
|
|
179
179
|
absent, with no error. `data://` and `packages://` index themselves seconds after a disk change —
|
|
180
180
|
the whole step. Any other source needs a sync:
|
|
181
181
|
`neuralis request POST @neuralis/brain-core/sources/sync -f source=<slug>` — it needs
|
|
182
|
-
`
|
|
183
|
-
around the gate — ask: files on disk, `
|
|
182
|
+
`sources.sync`, and **no tool syncs.** Lacking it, do not route
|
|
183
|
+
around the gate — ask: files on disk, `sources.sync` named, Files widget → Sources → `<slug>` →
|
|
184
184
|
**Sync** offered, in the words `references/test-and-ship.md` prescribes.
|
|
185
185
|
|
|
186
186
|
Reach paths in full:
|
|
@@ -193,19 +193,19 @@ This skill is open to everyone: you must know *why* something does not work. Fiv
|
|
|
193
193
|
decide how far you get — and the two ways to put a file down are gated differently. Missing one?
|
|
194
194
|
**Name it and stop**; never retry a denied call or route around it.
|
|
195
195
|
|
|
196
|
-
- **Writing with `fs_write`** (`
|
|
196
|
+
- **Writing with `fs_write`** (`files.write`) — absent from your inventory without it, and that
|
|
197
197
|
gate governs the write tool only.
|
|
198
|
-
- **Writing with the shell** (`execute` present + the source's policy, never `
|
|
199
|
-
gate wants
|
|
200
|
-
`policy=` row, uncovered paths denied. `
|
|
198
|
+
- **Writing with the shell** (`execute` present + the source's policy, never `files.write`) — the
|
|
199
|
+
gate wants `exec` on the dir you `cwd` into (that folder's rules) and `write` on every path you write, same
|
|
200
|
+
`policy=` row, uncovered paths denied. `files.write` off + `execute` on still ships.
|
|
201
201
|
- **Installing or building** (`packages.author`). Without it the Build and Install actions vanish
|
|
202
202
|
from the UI and those routes refuse you; code cannot be compiled, markdown needs neither.
|
|
203
203
|
- **Reading package diagnostics** (`core.observe`). Without it that response is forbidden. For an
|
|
204
204
|
installed package fall back to the server log naming your id; for a source package there is no
|
|
205
205
|
log line at all — read the source-package entries in your own `<packages>` block instead.
|
|
206
|
-
- **Indexing a source** (`
|
|
206
|
+
- **Indexing a source** (`sources.sync`) — only on a manual-trigger source; lacking it, ask as above.
|
|
207
207
|
|
|
208
|
-
**Path (c) needs no install, no build, no `packages.author`, no `
|
|
208
|
+
**Path (c) needs no install, no build, no `packages.author`, no `files.write`** — the shell gate
|
|
209
209
|
above, plus an indexing path. Proving it landed wants `core.observe` too. Find what you *can* reach
|
|
210
210
|
before reporting you cannot.
|
|
211
211
|
|
|
@@ -218,7 +218,7 @@ before reporting you cannot.
|
|
|
218
218
|
| write a `tools/*.json` or its handler | `references/tools-and-schemas.md` | the `$schema` string, the closed `x-neuralis` keys, banned inputs, result bounding |
|
|
219
219
|
| build a widget, dock item, or chat card | `references/surfaces-and-design.md` | the dock companion rule, the canonical entry root, the self-contained entry, renderer × trust, the design floor |
|
|
220
220
|
| write server-side code (`src/lifecycle.ts`, `src/routes/*`, `src/tools/*`) or a sandboxed package | `references/runtime-and-build.md` | the exported shape, output paths, route pattern/feature literals, the build |
|
|
221
|
-
| develop a
|
|
221
|
+
| develop a native package from ITS OWN repository, outside the host's tree — kernel deps, `tsconfig` with nothing to extend, where the gates actually run, and which of git / mount / dependency / publish makes it LOAD | `references/runtime-and-build.md` §7b | a hard kernel dependency giving one contract two module graphs; a `tsc` that cannot resolve inside the container while the package runs fine; assuming a pushed commit changed the deployment |
|
|
222
222
|
| call ANOTHER package's routes from sandboxed code (`ctx.callRoute`, the `ctx.fs.*` sugar, the per-package route catalog links) | `references/runtime-and-build.md` §6 | trusted-only, caller's real session, deny-by-default feature gates, writes land pending_review |
|
|
223
223
|
| attach an external system as a data source, set path permissions — or your connector never appears in `GET /connectors` | `references/connectors-and-uri-policies.md` | the connector port contract, which project a connector registers into (and when it registers into NONE), the admin-only write gate, `sources[]`, `uriPolicies` self-namespacing |
|
|
224
224
|
| need a secret, an API key, or any adjustable value | `references/config-and-credentials.md` | declare-don't-hardcode, credential scopes, shell env projection |
|
|
@@ -249,23 +249,23 @@ shell → `grep -rn "requiredFeatures" ${SKILL_DIR}/references/`.
|
|
|
249
249
|
Two scripts do the mechanical half:
|
|
250
250
|
|
|
251
251
|
```bash
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
node "${SKILL_DIR}/scripts/check-package.mjs" <absolute-package-root> # any path, before you ship
|
|
253
|
+
node "${SKILL_DIR}/scripts/verify-loaded.mjs" <package-id> # any path, after
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
-
`check-package.
|
|
256
|
+
`check-package.mjs` is static, needs no server, and modes off disk: with a manifest it runs
|
|
257
257
|
everything; with **none** it runs markdown mode — package recognition, the categories, every
|
|
258
258
|
frontmatter gate — then prints the manifest/tools/workflows/surfaces/runtime/dist checks it skipped,
|
|
259
|
-
so no skip reads as a pass. `verify-loaded.
|
|
259
|
+
so no skip reads as a pass. `verify-loaded.mjs` covers all three paths (for (c) pass
|
|
260
260
|
`<rootUri>?project=<p>&scope=…`) and reads package diagnostics, so it needs `core.observe` — lacking that it
|
|
261
261
|
reports it could not reach them rather than claiming the package is absent.
|
|
262
262
|
|
|
263
263
|
**Enable, trust, install and rescan apply from the NEXT stream.** A stream captures the set of
|
|
264
264
|
packages it may use once, at its start: a package you just enabled, trusted or installed becomes
|
|
265
265
|
activatable in the next stream — a new user message, a workflow run, a fresh conversation — never
|
|
266
|
-
mid-turn. A delegate spawned after the change sees its `<packages>` entry, injected
|
|
266
|
+
mid-turn. A foreground delegate spawned after the change sees its `<packages>` entry, injected
|
|
267
267
|
rules/instructions and agent resolution fresh, but its tool catalog and skill activation still
|
|
268
|
-
use the parent stream's gate. A `Skill not found` in
|
|
268
|
+
use the parent stream's gate; a background delegate re-reads all of them at its wake. A `Skill not found` in
|
|
269
269
|
the same continuous turn that flipped the package is this rule, not a broken package: retry from
|
|
270
270
|
a fresh stream before re-diagnosing.
|
|
271
271
|
|
|
@@ -48,13 +48,13 @@ Effective value cascade, exactly three steps: **platform file override → `envF
|
|
|
48
48
|
- **`envFallback` is ignored for `type:"json"`** (validation warning; the administrator sets the env var and nothing changes), and **`type:"json"` rows are excluded from the flat settings list** — the key still reads through the cascade, it is just not on the list.
|
|
49
49
|
- **`category: "vector"` is filtered out of the flat Platform Settings list** — a dedicated Vector section owns it, so any non-embedding key you file there is invisible in the admin UI.
|
|
50
50
|
- **Secret-shaped names are warned, not blocked.** A `key` or `envFallback` matching `secret|token|passw|credential|apikey|api_key|private` produces a manifest warning — and the value still renders as plaintext. Declare a credential instead.
|
|
51
|
-
- **Do not invent an `envFallback`.** It projects an arbitrary environment variable's VALUE into administrator-visible state — which is exactly why `configSettings[]` is honoured for **
|
|
51
|
+
- **Do not invent an `envFallback`.** It projects an arbitrary environment variable's VALUE into administrator-visible state — which is exactly why `configSettings[]` is honoured for **native** packages only.
|
|
52
52
|
|
|
53
53
|
**Declaration is not a grant.** A row registers a schema entry on the feature-gated admin Config surface. It gives your package no write authority over anything.
|
|
54
54
|
|
|
55
55
|
## Task — read a config value in your code
|
|
56
56
|
|
|
57
|
-
`ctx.config.get(key)` reads a declared platform setting live. Every
|
|
57
|
+
`ctx.config.get(key)` reads a declared platform setting live. Every native key is registered before `init`; an undeclared key throws. Reads below host-assigned native trust are denied.
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
60
|
import type { PackageInitContext } from '@neuralis/package-system/contracts';
|
|
@@ -80,8 +80,8 @@ The shape is exactly `{ id, label, category?, oauth? }` — `id` and `label` req
|
|
|
80
80
|
|
|
81
81
|
- **`id` must pass `^[A-Za-z_][A-Za-z0-9_.-]*$`, at most 128 chars.** The id becomes an `<id>.enc.json` path segment, so a slash, whitespace or a leading dot is rejected — an id can never escape its scope directory. Duplicate ids in one manifest, a missing `id`/`label`, or a non-object entry all fail validation with a named error.
|
|
82
82
|
- **Declare only what something RESOLVES.** A catalog row an owner fills in that no code reads is worse than no row — the operator believes the key is configured while the feature stays dark. A drift guard asserts declarations and consumers match **in both directions**, so a dead declaration fails the build. Boot-critical infrastructure read from the environment (a vector-DB key wired before any credential can be decrypted) belongs in `.env`, not here.
|
|
83
|
-
- **Reserved namespaces are
|
|
84
|
-
- **The catalog is dynamic**: the union of package `credentials[]`, every installed skill's `credentials:` frontmatter, and ids already stored by hand. Entries carry only `hasValue`, never the value. There is **no visibility trust gate** — your package's own ids appear at any trust tier, or an owner could never set them. Trust governs ATTRIBUTION instead: a
|
|
83
|
+
- **Reserved namespaces are native-only.** The git (`git.<host>.pat`, `git.<host>.oauth.*`), channel, and MCP (`mcp.<server>.*`) id classes have host-owned resolution semantics — a resolver reads them at a member's OWN scope on that member's behalf — so a non-native manifest declaring one is a **validation error, not a warning**: unlike a retired key, it fails the manifest and the package does not load. Squatting `git.github.com.pat` would otherwise put a token an owner filled in at global scope into the cascade for every member without their own. Declare ids in your own namespace (`acme.apiKey`).
|
|
84
|
+
- **The catalog is dynamic**: the union of package `credentials[]`, every installed skill's `credentials:` frontmatter, and ids already stored by hand. Entries carry only `hasValue`, never the value. There is **no visibility trust gate** — your package's own ids appear at any trust tier, or an owner could never set them. Trust governs ATTRIBUTION instead: a native declaration wins the label/category, a later declarer only joins the `declaredBy` list, and the UI renders the trust tier next to a non-native declarer.
|
|
85
85
|
- **Declaration is not a grant here either.** A row is catalog metadata; it confers no write authority, and consumption still resolves against the caller's real scope.
|
|
86
86
|
- **`oauth: true` is a DISPLAY hint only** — it changes admin chrome to Connect/Disconnect. It gives you no OAuth flow, and on an unwired provider the row is a dead button.
|
|
87
87
|
|
|
@@ -112,19 +112,22 @@ description: Fetch a city forecast via the Weather API.
|
|
|
112
112
|
credentials:
|
|
113
113
|
- WEATHER_API_KEY
|
|
114
114
|
---
|
|
115
|
-
Run: `
|
|
115
|
+
Run: `node "${SKILL_DIR}/scripts/forecast.mjs" "$CITY"`
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
```js
|
|
119
|
+
// skills/forecast/scripts/forecast.mjs
|
|
120
|
+
const key = process.env.WEATHER_API_KEY;
|
|
121
|
+
if (!key) { process.stderr.write('WEATHER_API_KEY is not configured — set it under Credentials\n'); process.exit(2); }
|
|
122
|
+
const res = await fetch(`https://api.weather.example/v1/forecast?q=${encodeURIComponent(process.argv[2] ?? '')}`, { headers: { Authorization: `Bearer ${key}` } });
|
|
123
|
+
const body = await res.text();
|
|
124
|
+
if (!res.ok) { process.stderr.write(`HTTP ${res.status}\n${body}\n`); process.exit(1); } // keep the error body
|
|
125
|
+
process.stdout.write(body);
|
|
123
126
|
```
|
|
124
127
|
|
|
125
128
|
On activation the host resolves each declared id at the caller's real `(userId, projectId, agentId)` scope, within the caller's tier ceiling: own user key always; agent and project keys with `project.credentials.write`; global with `platform.scope` too. A tier above it reads as missing, so a member's run needs the member's own key (`credentials.self`). **The model never sees a resolved value.**
|
|
126
129
|
|
|
127
|
-
- **`credentials:` must be a list of plain strings.** A scalar or a list of objects is dropped silently by the whitelist frontmatter parser: the skill activates normally, the catalog shows no ids, and your script exits on
|
|
130
|
+
- **`credentials:` must be a list of plain strings.** A scalar or a list of objects is dropped silently by the whitelist frontmatter parser: the skill activates normally, the catalog shows no ids, and your script exits on its missing-key guard with no parse error anywhere.
|
|
128
131
|
- **A missing value is non-fatal.** The id lands on a `missing` list, the rendered body carries a `(missing: <id>)` marker, and no variable is set — which is why scripts should fail with a message pointing the user at the Credentials surface.
|
|
129
132
|
- **Sanitise exactly once.** Pass `env` and the allow-list straight through to the shell runner. A second defensive sanitise pass has no allow-list and strips exactly the credential keys that were just projected — and the symptom, "the credential is configured but the script says it is missing", sends you debugging the wrong layer.
|
|
130
133
|
- **The allow-list applies to the OVERRIDES side only.** It never un-strips a same-named variable already present in the host process environment. That is deliberate: a leaked host secret must not piggyback on an allow-listed name.
|
|
@@ -153,10 +156,10 @@ Never inline a secret in a manifest or a source config file, and never default-a
|
|
|
153
156
|
## What works on which reach path
|
|
154
157
|
|
|
155
158
|
- **Installed package (in-process):** the only path where both halves work fully. Trust comes from being installed, so keys register at boot, the Config tab shows your package as declarer, `ctx.credentials` is available, and skill `credentials:` projects into script environments.
|
|
156
|
-
- **Project `_packages/` drop (sandboxed, untrusted):** `configSettings[]` is **silently dropped** — the only trace is a `config.declaration_skipped` warning, nothing fails at install time, and the first `get()` throws `Config key not registered`. The sandbox bridge exposes no config and no credential host function at all, so declared `credentials[]` still show in the catalog but sandboxed code cannot read a value. Take tunables as tool inputs or from your own data files, and do not plan on secret access. **An admin can elevate a dropped package to `trusted`, never to
|
|
159
|
+
- **Project `_packages/` drop (sandboxed, untrusted):** `configSettings[]` is **silently dropped** — the only trace is a `config.declaration_skipped` warning, nothing fails at install time, and the first `get()` throws `Config key not registered`. The sandbox bridge exposes no config and no credential host function at all, so declared `credentials[]` still show in the catalog but sandboxed code cannot read a value. Take tunables as tool inputs or from your own data files, and do not plan on secret access. **An admin can elevate a dropped package to `trusted`, never to native** — the drop path pins `untrusted` and the elevation channel has no native value — so neither array ever comes back on this path. If you need declared config or credential access, ship the package on the installed path instead.
|
|
157
160
|
- **Source markdown package (no install step):** no manifest, so neither array exists on this path. Per-skill `credentials:` frontmatter still works exactly as above — a source-package skill can shell out with a secret in its environment; it just cannot declare a tunable or a catalog row of its own.
|
|
158
161
|
|
|
159
162
|
## Going deeper
|
|
160
163
|
|
|
161
164
|
- Configuration tiers and the cascade: <https://docs.neuralisapp.com/enterprise/configuration>
|
|
162
|
-
- Credential scopes, the dynamic catalog and the encrypted store: <https://docs.neuralisapp.com/
|
|
165
|
+
- Credential scopes, the dynamic catalog and the encrypted store: <https://docs.neuralisapp.com/package-system/credentials>
|
|
@@ -28,6 +28,9 @@ The dataset lives only behind the configured source/connector. An arbitrary writ
|
|
|
28
28
|
{ "id": "acme-mcp", "type": "mcp", "transport": "stdio", "command": "npx",
|
|
29
29
|
"args": ["-y", "@acme/mcp-server"],
|
|
30
30
|
"auth": { "type": "env-vars", "envVarName": "ACME_TOKEN" } },
|
|
31
|
+
{ "id": "acme-remote", "type": "mcp", "transport": "streamable-http",
|
|
32
|
+
"url": "https://mcp.acme.test/mcp", "name": "Acme", "description": "Orders and invoices",
|
|
33
|
+
"auth": { "type": "oauth2", "scopes": ["read"] } },
|
|
31
34
|
{ "id": "acme-api", "type": "openapi",
|
|
32
35
|
"openApiSpec": "https://api.acme.test/openapi.json",
|
|
33
36
|
"openApiOperationFilter": { "include": ["listOrders", "getOrder"] },
|
|
@@ -41,18 +44,19 @@ The dataset lives only behind the configured source/connector. An arbitrary writ
|
|
|
41
44
|
- `auth.type` is closed: `none | api-key | bearer-token | basic | oauth2 | oauth2-pkce | env-vars`. `env-vars` is the one for a stdio MCP subprocess — decrypted values go into the child process env.
|
|
42
45
|
- **Secrets are collected through `auth.setupFields[]`** (shape in `references/config-and-credentials.md`). There is no `credentialRef` auth field; writing one collects nothing and the connector starts unauthenticated.
|
|
43
46
|
- A `type: "source"` entry is handled only by the source pipeline; the outbound lifecycle skips it.
|
|
47
|
+
- **A remote `mcp` row is offered to the user, never auto-connected.** It needs `transport: "streamable-http"` and a `url` (a package fails validation otherwise; `stdio` + `command` is the trusted sidecar form above), and it is never registered as a connector. Every agent whose owner may see the package — its base-access feature, and the package switched on for that agent — gets it under Connections → MCP servers as "Offered by <package>" (and as an `offered` row of `connect {list:{kind:"mcp"}}`); Add, or `connect {add:{kind:"mcp", offer:"<packageId>#<connectorId>"}}`, adopts it as that agent's own MCP server and signs in through the server's OAuth (discovery, dynamic client registration, PKCE). Only `url`, `name`, `description`, `icon` and `auth.scopes` are read; `auth.type` is `oauth2`, `oauth2-pkce` or `none`, and any other type is not offered. No MCP request reaches the server before the user signs in (the sign-in reads its OAuth metadata and registers a client), no Neuralis identity header is ever sent, and an adopted server stays the user's when the package is later switched off.
|
|
44
48
|
|
|
45
49
|
### Which tenant an outbound connector registers into
|
|
46
50
|
|
|
47
51
|
A `connectors[]` entry is **not** registered once for the whole deployment. It lands in exactly one **partition**, and which one is decided by how the package reached the host — never by anything you can write in the manifest:
|
|
48
52
|
|
|
49
|
-
- **Installed package,
|
|
53
|
+
- **Installed package, native** → the **platform lane**. One registration, visible in every project on the deployment. It is the only lane a package with no owning project may reach.
|
|
50
54
|
- **Project `_packages/` drop** → **that project's own partition**. The connector exists for that project and nowhere else; two projects dropping the same package get two independent connectors with independent config, status and health.
|
|
51
|
-
- **No resolvable owning project and not
|
|
55
|
+
- **No resolvable owning project and not native → NOTHING is registered.** Fail-closed on purpose: the only partition left would be the platform lane, which every project can see. **This is the first thing to check when a connector "disappeared"** — the package loads clean, `check-package.mjs` is happy, the manifest is valid, and `GET /connectors` simply never lists it. The only trace is the server line `Connector registration refused: unresolved owning project`. Nothing in the manifest will fix it; find why the package has no owning project.
|
|
52
56
|
|
|
53
57
|
Reads follow the same partition. `GET /connectors` answers with the caller's own visibility — the platform lane UNION their project — and an id-addressed call resolves own-project first, then platform. An id belonging to **another** project answers the same generic **`404 Not found`** as an unknown id or a malformed one: the three are deliberately indistinguishable, so no caller can enumerate another project's connector ids out of the error text. Do not build a retry, a fallback or a "does it exist elsewhere" probe on that 404 — it will never become a more specific code.
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
A remote MCP row never takes this path: it is an offer each agent adopts (above), so its tools reach exactly the agents that added it.
|
|
56
60
|
|
|
57
61
|
**Reading is not writing.** Listing connectors, reading one's health and reading its resolved tools ride the module's `core.observe`. Every MUTATING arm — create, delete, configure, connect, disconnect, enable, disable — additionally requires the **`core.connectors`** feature — granted to `admin` by default, reached by an owner-strength role through its `'*'` wildcard, and held by no one else. A caller who can SEE a connector row and gets `403 Forbidden` on Connect is looking at that gate, not at a broken connector: name the feature and stop. Never retry it, and never reach for another identity.
|
|
58
62
|
|
|
@@ -93,16 +97,26 @@ None of this touches a `type: "source"` entry. A filesystem kind is registered a
|
|
|
93
97
|
1. **Omitting `"additionalProperties": false` is PERMISSIVE, not rejecting.** Arbitrary unvalidated keys land in your factory's `config`; the rejection you assumed was happening never happens.
|
|
94
98
|
2. **It is a hand-rolled draft-07 SUBSET.** Supported: top-level `type: "object"`, `required`, `additionalProperties: false`, and per-property `type`, `enum`, `const`, `minLength`, `maxLength`, `pattern`, `minimum`, `maximum`, `items`. Everything else — `$ref`, `oneOf`/`anyOf`/`allOf`, `format`, `dependencies`, nested object schemas — is **silently ignored**: no error, no warning, invalid config reaching your factory as a type crash deep inside the connector. Keep the form flat.
|
|
95
99
|
|
|
96
|
-
3. **A `root` property
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
3. **A `root` property declares `"control": "container-path"`** (the bare legacy `"path"` still
|
|
101
|
+
works the same): the path lives on the app's own machine — in a Docker install the container,
|
|
102
|
+
where the form suggests the `/mounts` binds and the `neuralis mount add` callout; on a native
|
|
103
|
+
install only the project's own folder, any other folder being attached on the user's paired
|
|
104
|
+
device. `"browse": true` offers the folder picker. Declare `label` and `placeholder` too: the
|
|
105
|
+
form uses yours, and a kind that declares neither renders a bare `Path` with an empty
|
|
106
|
+
placeholder. One kind may serve both planes: a field marked `"transport": true` (the `host`
|
|
107
|
+
kind's `device`) renders BEFORE the root and, while it holds a value, turns the root into a path
|
|
108
|
+
on that device — your `deviceLabel`/`devicePlaceholder` (or a `devicePlaceholders` entry per
|
|
109
|
+
the chosen row's `platform`: `win32` · `darwin` · `linux`), browsed through that device's broker —
|
|
110
|
+
and a schema-level `"not": {"required": ["device", "hostRoot"]}` both refuses the pair and hides
|
|
111
|
+
the excluded field. `"advanced": true` folds a field under "Advanced" and `"help"` is its short
|
|
112
|
+
line; the schema-level `"x-neuralis": {"ui": {"summary": "…"}}` is the kind's one-line form text
|
|
113
|
+
(your `description` stays the agent's).
|
|
114
|
+
4. **Any other field is a text input, or a `select` filled by YOUR route.** `"control": "select",
|
|
115
|
+
"optionsRoute": "things?scope=mine"` makes the form read that relative route of your own package and
|
|
116
|
+
offer the first array in the JSON answer as rows `{id, name?, platform?, status?}` (value = `id`; a
|
|
117
|
+
`revoked` row is not offered). An absolute route, a scheme or a `..` segment is refused and the
|
|
118
|
+
field falls back to text with the reason. With `"optional": true` the select also offers the
|
|
119
|
+
empty value as a real choice, labelled `emptyLabel`. The list is UX only: re-check the value in your connector.
|
|
106
120
|
|
|
107
121
|
**Never put a secret in `configSchema`.** There is no `credentialFields[]` key that splits schema properties into the credential store, and the factory context carries no `credentials` map — a config property IS plain config, persisted in `sourceConfig.json`. Declare the secret in `neuralis.credentials[]` and read it through the `CredentialResolver` the loader injects into your package's `init(ctx)` — **that** `ctx`, not the factory's — and let the factory close over the resolver. Rules in `references/config-and-credentials.md`.
|
|
108
122
|
|
|
@@ -127,7 +141,7 @@ export function createNotesConnector(ctx: ConnectorFactoryContext): ConnectorPor
|
|
|
127
141
|
}
|
|
128
142
|
```
|
|
129
143
|
|
|
130
|
-
- **Declared capabilities must EXACTLY equal the runtime set**, both directions. Closed vocabulary: `list`, `read`, `stat`, `write`, `delete`, `move`, `mkdir`, `rmdir`, `exec`, `execDetached`, `scanDelta`, `walk`, `count`, `peekCount`, `scanContent`, `subscribeEvents`, `resolveOsUri`; `list` and `read` are mandatory, each of the rest gates one optional method. Symptom: `connector.source.capability-mismatch` with declared-vs-actual sets, thrown at **per-source instantiation** — "installed fine, breaks the first time someone creates a source of this kind."
|
|
144
|
+
- **Declared capabilities must EXACTLY equal the runtime set**, both directions. Closed vocabulary: `list`, `read`, `stat`, `write`, `delete`, `move`, `mkdir`, `rmdir`, `exec`, `execDetached`, `scanDelta`, `walk`, `count`, `peekCount`, `scanContent`, `subscribeEvents`, `resolveOsUri`; `list` and `read` are mandatory, each of the rest gates one optional method. Symptom: `connector.source.capability-mismatch` with declared-vs-actual sets, thrown at **per-source instantiation** — "installed fine, breaks the first time someone creates a source of this kind." Native ⇒ boot-fatal; otherwise the kind goes unavailable and callers get `ConnectorCapabilityMissing`.
|
|
131
145
|
- **Pin the implemented ABI: `4 satisfies ConnectorPortVersion`.** A package shipped SEPARATELY from the kernel pins the number it was built against — importing the host's runtime constant makes an old binary relabel itself as current on the next platform upgrade, which is the one failure the version check exists to catch. (A connector that ships IN LOCKSTEP with the kernel may import the constant instead; yours does not.) Older exec signatures are rejected without adaptation; version equality alone does not prove external code enforces authorization.
|
|
132
146
|
- **Exec is authenticated, and you do NOT write the entry check.** `exec({ command, cwd, timeout?, env?, background? }, { session, signal? })` receives the real `SessionContext` and exact source URI. Declaring the `exec` capability REQUIRES declaring `"execRequires": ["<feature.id>", …]` beside it — the feature id(s) that open a shell on your kind. A missing or EMPTY list is a manifest error, because "every id in an empty list is held" is a door that is always open. The platform stamps a frozen copy of those ids on the instance and wraps `exec` so each one is checked before your code runs, and the calling tool then evaluates the SOURCE's own uri-policy `exec` bit on the cwd. So enforce your lifecycle and supported options — not the entry feature; a second copy in your provider would be free to drift from your manifest. Return the existing result fields plus optional bounded `text`. Exec bindings require an absolute factory `projectRoot`. The loader snapshots provider/source/project/scope before factory execution and stamps the checked instance; callers verify `getConnectorBindingProvenance` against current authority. Never reuse one instance across bindings.
|
|
133
147
|
- **A run that OUTLIVES its call is `execDetached` + the `detached` facet.** Declare the capability (it also requires `exec`) and implement all FIVE verbs — `start`, `status`, `output`, `kill`, `release` — or the loader refuses the binding: a declared capability with a missing verb is a run the platform can start and never stop. `start(request, context)` is a second exec ENTRY, so the platform wraps it with your `execRequires` exactly like `exec`; the other four take the run id you returned and NOTHING else, because a caller who has since lost the entry feature must still be able to read and stop their own run. Ownership is the platform's stored record, never a claim in your arguments: the optional `actor` on `kill` is for your audit row only. Report a kill as an ACKNOWLEDGEMENT and the real end through `status`; answer `null` for a run you no longer know, and keep `output` rows monotonic by `seq` so the platform can prove it copied the whole log before it reports the run finished.
|
|
@@ -151,12 +165,12 @@ export function createNotesConnector(ctx: ConnectorFactoryContext): ConnectorPor
|
|
|
151
165
|
]
|
|
152
166
|
```
|
|
153
167
|
|
|
154
|
-
Required: `source` (unique slug), `kind`, `scope` ∈ `project|user|agent`, a non-empty `description`, `seed` ∈ `auto|discoverable`. Optional: `root`, `label`, `sync`, `permissions`, `
|
|
168
|
+
Required: `source` (unique slug), `kind`, `scope` ∈ `project|user|agent`, a non-empty `description`, `seed` ∈ `auto|discoverable`. Optional: `root`, `label`, `sync`, `permissions`, `packageFolders`, `visibility.seeRequires`.
|
|
155
169
|
|
|
156
|
-
- `seed: "auto"` seeds into every project with no human in the loop → requires **trusted or better**, else `seed="auto" requires trust >= 'trusted'` and the package fails to load. A root naming a platform token (`${appRoot}`) requires **
|
|
170
|
+
- `seed: "auto"` seeds into every project with no human in the loop → requires **trusted or better**, else `seed="auto" requires trust >= 'trusted'` and the package fails to load. A root naming a platform token (`${appRoot}`) requires **native**. Otherwise roots must be project-relative: no leading `/`, no `${…}` token, no `.` / `..` segments.
|
|
157
171
|
- An untrusted drop gets `seed: "discoverable"` with a project-relative root and nothing more — its declarations never enter the trusted attribution map, so the source appears unattributed, with no package-supplied label or description.
|
|
158
172
|
- **`visibility.seeRequires` is a UX default, not the gate.** The authoritative see-filter and the add-feature check live server-side. Ship a source believing `seeRequires` hides it and you have shipped an unhidden source; setting it grants nothing either.
|
|
159
|
-
- **`
|
|
173
|
+
- **`packageFolders` does NOT switch markdown discovery on.** Default unset (⇒ none); `[""]` makes the whole declared `host` source one package folder, `["a/b"]` one folder under its root — the same field the created source stores (`packageFolders may only be set when connection.kind is "host".`), settable only by an owner/admin-effective caller (`Setting packageFolders requires an owner/admin-effective role.`). Its real job is the *code-LOAD* axis: the host scans each package folder of an enabled folder it can open for **installable** packages, the way it always scans the project `packages` drop-zone (which needs no flag); a package folder on a paired device loads over the device link while the device is online, and while it is offline the package stays listed as not available. A loaded package's source twin is not injected twice — the dedup is by exact origin. **Symptom when unset: none for markdown.** A plain synced folder still contributes skills, instructions, rules, agents and docs by folder layout alone — recognition criteria are the reach-path table in `SKILL.md` (column (c)) and the discovery rules in `references/manifest-and-discovery.md`. If a source package is invisible, this flag is not the cause; work the diagnosis table below.
|
|
160
174
|
|
|
161
175
|
## Set path permissions (`uriPolicies`)
|
|
162
176
|
|
|
@@ -170,24 +184,24 @@ An **object keyed by URI pattern** — not an array, and no `access` enum. The p
|
|
|
170
184
|
{ "pattern": "data://<self>/private/**", "permissions": { "read": false } },
|
|
171
185
|
{ "pattern": "data://<self>/private/$self/**", "permissions": { "read": true }, "override": true },
|
|
172
186
|
{ "pattern": "data://<self>/private/**", "permissions": { "read": true },
|
|
173
|
-
"
|
|
187
|
+
"priority": 2, "override": true } ] } }
|
|
174
188
|
```
|
|
175
189
|
|
|
176
190
|
1. **Every key must start with `packages://<self>/` or `data://<self>/`** (or equal that prefix minus the trailing slash). A foreign namespace — another package's id, `app://`, `neuralis://`, a bare OS path — **rejects the WHOLE manifest**: no partial registration, the package does not load at all. Inner `paths[].pattern` entries containing `://` are checked identically; relative inner patterns pass.
|
|
177
191
|
2. **`<self>` is a load-time placeholder** substituted with your package slug at boot. Never hardcode your own id in a key.
|
|
178
192
|
3. **`$self`, `$creator`, `$source` are a DIFFERENT family** — runtime tokens substituted inside `paths[].pattern` with the caller's agent id, the source creator's user id, and the source slug. Confusing them is the classic failure: `<self>` in a path position becomes a literal, never-matching segment (the rule appears to do nothing); `$self` in a *key* is not substituted at load, fails the prefix check, and rejects the manifest. This pair is also how self-maintaining identity works: `data://<self>/$self/**` writable while `data://<self>/*/**` is not means an agent rewrites its own identity files and no one else's — a uri-policy grant, not a special case.
|
|
179
193
|
4. **Every value needs `default: { read, write, exec }`, all three booleans present**, or the manifest fails with `missing required default { read, write, exec } booleans`. **Every `paths[]` row needs its capabilities nested under a `permissions` object**, not at the row's top level — the top-level spelling used to normalize to `permissions: {}` and the rule became SILENTLY INERT (it read like a real deny in the manifest and in every persisted copy of it). It is now a load-time rejection, so an inert row cannot ship.
|
|
180
|
-
5. **Patterns match the FULL URI** (leading slash stripped): `?` = one non-separator char, `*` = a run of non-`/`, `**` = anything including `/`, a leading `**/` may match zero segments, anchored both ends. Two symptoms follow: a source-relative pattern (`memory/**` instead of `data://<self>/memory/**`) **silently never matches**, so the intended deny is absent and access falls back to `default`; and `data://<self>/**` does **not** cover the bare root `data://<self>`, so directory-level denies leak on the directory node itself. Spelling is NOT one of the symptoms: slash runs, `.` and `..` are canonicalized on the pattern AND on the URI under test before matching (see the floor paragraph below), so you cannot miss a rule by writing it non-canonically and no caller reaches a file by rewriting its URI.
|
|
194
|
+
5. **Patterns match the FULL URI** (leading slash stripped): `?` = one non-separator char, `*` = a run of non-`/`, `**` = anything including `/`, a leading `**/` may match zero segments, anchored both ends. Two symptoms follow: a source-relative pattern (`memory/**` instead of `data://<self>/memory/**`) **silently never matches**, so the intended deny is absent and access falls back to `default`; and `data://<self>/**` does **not** cover the bare root `data://<self>`, so directory-level denies leak on the directory node itself. Spelling is NOT one of the symptoms: slash runs, `.` and `..` are canonicalized on the pattern AND on the URI under test before matching (see the floor paragraph below), so you cannot miss a rule by writing it non-canonically and no caller reaches a file by rewriting its URI. Letter case is handled too: a rule's `false` bits match every case of its pattern (`CONVERSATIONS/` hits a `conversations/**` deny on every OS), its `true` bits only the exact spelling — write patterns in the case your package creates the files.
|
|
181
195
|
|
|
182
|
-
**Evaluation order:** `default` → `byRole` → `byUser` → `byAgent` → `paths`. Path rules are **deny-wins**: a `read: true` rule applies only when the result is not already `false`. To re-open something a broader rule denied, set `override: true` — otherwise the carve-out looks correct in the manifest and the caller still gets 403. Rules narrow with `
|
|
196
|
+
**Evaluation order:** `default` → `byRole` → `byUser` → `byAgent` → `paths`. Path rules are **deny-wins**: a `read: true` rule applies only when the result is not already `false`. To re-open something a broader rule denied, set `override: true` — otherwise the carve-out looks correct in the manifest and the caller still gets 403. Rules narrow with `priority`, `users[]` and/or `agents[]`; every condition present on one rule must hold, so "A or B" is two rules.
|
|
183
197
|
|
|
184
|
-
**`byRole` is keyed by name but resolved by STRENGTH;
|
|
198
|
+
**`byRole` is keyed by name but resolved by STRENGTH; a path rule names its subject by the caller's role priority with `priority`.** Do not treat them as one mechanism. A `byRole` entry applies to the caller whose role NAME matches, else to the caller at that entry's exact declared `priority` (so a custom role at the owner anchor gets the `owner` entry), else — for every entry belonging to a role at least as strong as the caller — its explicit `false` bits only, never a grant. A role weaker than `viewer` therefore INHERITS viewer's denials instead of escaping them, and an `owner` never inherits a viewer restriction. On a `paths[]` rule, `"priority": 2` matches every caller whose role priority is n or stronger (`<= 2`; lower = stronger: owner 1, admin 2, manager 10, member 20, viewer 30), a custom role at that strength included — it is the caller's role strength, not the rule's order. It fails closed: a value that is not an integer from 1 to 99, or a caller without a priority, never matches, and the manifest is rejected. `priority` is grant-only (`override: true`, every declared bit `true`), never on a deny or `floor: true` row. `paths[].roles[]` is rejected in a manifest (`roles is not allowed in a package manifest`): it matches a role NAME exactly, and only a project's own stored rules may use it.
|
|
185
199
|
|
|
186
200
|
**Uncovered paths deny by default.** A filesystem-touching package with no policy baseline is not "open" — it is denied everywhere and its writes fail quietly. Missing path policy is a bug to flag, never a passing state.
|
|
187
201
|
|
|
188
202
|
**`exec` is the dimension the sandboxed shell reads.** Keep it `false` on a data zone. The other direction's symptom: `execute action=shell` denies on the cwd with `capability: 'exec'` and `Source "<slug>" denies shell execution (exec) to this caller`, though reads and writes there succeed.
|
|
189
203
|
|
|
190
|
-
**Your baseline's `default` applies to YOUR PATTERN, not to the source.** The key you declare (`data://<self>/**`) scopes the whole entry: at seeding, that `default` block becomes a path RULE on that pattern, and the source keeps its own source-level default. This is why a `default: { exec: false }` in your manifest does not — and must not — turn off `exec` for the entire shared `data` source that every other package also declares against. One consequence worth knowing:
|
|
204
|
+
**Your baseline's `default` applies to YOUR PATTERN, not to the source.** The key you declare (`data://<self>/**`) scopes the whole entry: at seeding, that `default` block becomes a path RULE on that pattern, and the source keeps its own source-level default. This is why a `default: { exec: false }` in your manifest does not — and must not — turn off `exec` for the entire shared `data` source that every other package also declares against. One consequence worth knowing: the shell and terminal judge `exec` on the working directory, so your manifest `exec:false` stops a shell from STARTING anywhere under your subtree (and binds the brain-core git remote-op gate) — but a command started elsewhere can still run a script it can read from there. Use a `floor: true` row for anything that must actually be unreachable.
|
|
191
205
|
|
|
192
206
|
**Two limits on where your baselines land — and the one exception that is not limited.** Manifest `uriPolicies` baselines are seeded **only at first source attach, and only for source slugs literally named `data` or `packages`** — declare them expecting them to apply to a custom slug (`repo`, `machine`) and nothing happens; the persisted config is used verbatim. And **a new non-floor pattern in an updated package version does not reach existing installs**: only brand-new sources get it, pre-existing projects keep the old permissions indefinitely, and reaching them takes a version-stamped baseline repair pass. Plan for that whenever you tighten a shipped policy.
|
|
193
207
|
|
|
@@ -206,7 +220,7 @@ Denial surfaces as `uri_policy_denied` (HTTP 403, structured body with `uri` and
|
|
|
206
220
|
| Refused, source slug unknown here | `source_not_configured` (`nextStep: check_configured_sources`, HTTP 404) | no persisted SourceConfig for that slug in this project — or one scoped to someone else, which answers identically. NB the uri gate runs FIRST and denies an unconfigured source as `uri_policy_denied`, so this code surfaces on the routes with no pre-guard (`list`) and for scheme-less uris — a scheme-bearing guess usually reads as the 403 row above | read the reply's `availableSources` (the caller's own visible set) and address one of those; retrying the same slug never helps |
|
|
207
221
|
| Kind absent from the picker | *(log only)* | manifest entry incomplete, factory unresolvable, or trust rejected | read the server log line |
|
|
208
222
|
| A mutating connector call refused while listing works | `403 Forbidden` on a `/connectors` write arm | the caller holds `core.observe` but not `core.connectors` | an admin performs it, or the feature is granted — never retry |
|
|
209
|
-
| An outbound connector is listed nowhere, package `loaded` | *(log only:* `Connector registration refused: unresolved owning project`*)* | the package is not
|
|
223
|
+
| An outbound connector is listed nowhere, package `loaded` | *(log only:* `Connector registration refused: unresolved owning project`*)* | the package is not native and has no owning project, so it was registered into NO partition | resolve the owning project; the manifest is not the problem |
|
|
210
224
|
| Readable but invisible to semantic search | *(none)* | sync-excluded path — on disk, never indexed | do not conclude the file is missing |
|
|
211
225
|
|
|
212
226
|
**Policy and enabled are orthogonal; the enabled check runs right after visibility** (a source you cannot see answers as absent, before any enabled or policy answer). Policy answers *which URIs you may touch*; the enable toggle (`true | false | 'auto'`, where `'auto'` derives from the connector runtime probe) answers *whether the source is live at all*. Conflate them and users flip the wrong switch.
|
|
@@ -215,7 +229,7 @@ Denial surfaces as `uri_policy_denied` (HTTP 403, structured body with `uri` and
|
|
|
215
229
|
|
|
216
230
|
Live and enforced before any handler runs, where a **deny is absolute**. Three kinds compile:
|
|
217
231
|
|
|
218
|
-
- **`safety`** — `config.blockedTools: string[]` is a tool blocklist and `config.timeoutMs` **plus** `config.target` is a per-tool timeout (`target` = a tool name, `*`, or a `fs_*` prefix; smallest matching timeout wins). Either half alone compiles to nothing. Both are **global** — a blocked name is denied for every caller and every package, not only yours — and that is exactly why they are **
|
|
232
|
+
- **`safety`** — `config.blockedTools: string[]` is a tool blocklist and `config.timeoutMs` **plus** `config.target` is a per-tool timeout (`target` = a tool name, `*`, or a `fs_*` prefix; smallest matching timeout wins). Either half alone compiles to nothing. Both are **global** — a blocked name is denied for every caller and every package, not only yours — and that is exactly why they are **native-only**: from an installed or dropped package both are dropped at load, with a warning naming the kind. Do not reach for `safety` to restrict your own tools; `permission` does that at every trust level.
|
|
219
233
|
- **`permission`** — `config.allowedTools: string[]`, an allowlist scoped to the declaring package. It also filters the visible tool catalog, so a denied tool is hidden, not merely refused.
|
|
220
234
|
- **`trust`** — `config.enforceInputValidation: boolean`.
|
|
221
235
|
|
|
@@ -225,4 +239,4 @@ Two rules you never write are synthesized for every package: a **trust-tier ceil
|
|
|
225
239
|
|
|
226
240
|
---
|
|
227
241
|
|
|
228
|
-
Public reference: [connectors](https://docs.neuralisapp.com/package-system/connectors) · [URI policies](https://docs.neuralisapp.com/package-system/uri-policies) · [sources and connectors in the brain](https://docs.neuralisapp.com/brain-core/
|
|
242
|
+
Public reference: [connectors](https://docs.neuralisapp.com/package-system/connectors) · [URI policies](https://docs.neuralisapp.com/package-system/uri-policies) · [sources and connectors in the brain](https://docs.neuralisapp.com/brain-core/connectors)
|
|
@@ -91,7 +91,7 @@ Four skill layouts are recognised, not one — `skills/<name>/SKILL.md`, `<root-
|
|
|
91
91
|
|
|
92
92
|
## Trust and runtime
|
|
93
93
|
|
|
94
|
-
**Trust is assigned by where the package came from, never declared.** `access.trust` is `
|
|
94
|
+
**Trust is assigned by where the package came from, never declared.** `access.trust` is `native | trusted | untrusted`. A package installed as a dependency of the host is made `native` by the host after its manifest is read; a project-dropped package is pinned `untrusted` on its seed *before* the manifest merge, and the seed wins. Wherever the host assigns nothing, an **absent value means `untrusted`** — so `"access": {"trust": "native"}` in a package the host did not install as a dependency changes nothing.
|
|
95
95
|
|
|
96
96
|
Untrusted implies, all at once: rules physically moved into the `docs` array (so they never inject into the system prompt), `activation.target: prompt-context` rewritten to `workspace`, `overwrite` forced false, `skillScripts` restricted to `"none"`, no `permissions.exec`, no `net: "full"`, no `fs: "full"`, no `seed: "auto"` sources.
|
|
97
97
|
|
|
@@ -101,15 +101,15 @@ Untrusted implies, all at once: rules physically moved into the `docs` array (so
|
|
|
101
101
|
|
|
102
102
|
The three differ on two axes — LANGUAGE and CONFINEMENT — and only one of them gives a dropped package the second:
|
|
103
103
|
|
|
104
|
-
- **`node`** — in-process, **
|
|
105
|
-
- **`wasm`** — JS/TS compiled into an Extism sandbox. **The only code runtime available below
|
|
106
|
-
- **`mcp`** — any language, as an stdio subprocess. Also **
|
|
104
|
+
- **`node`** — in-process, **native only**.
|
|
105
|
+
- **`wasm`** — JS/TS compiled into an Extism sandbox. **The only code runtime available below native**, and what a dropped package declares to run code.
|
|
106
|
+
- **`mcp`** — any language, as an stdio subprocess. Also **native only**: the child runs as the host user, with the host's filesystem and network reach, from the `entry.command` and `entry.args` your manifest names. It is a LANGUAGE escape hatch, never a confinement one. Pair it with `entry.command` or you get a warning.
|
|
107
107
|
|
|
108
|
-
**Neither `node` nor `mcp` is rejected below
|
|
108
|
+
**Neither `node` nor `mcp` is rejected below native — both are DEMOTED.** The package warns and loads `partial`, reason `untrusted-node` or `untrusted-mcp`: declarative contributions register normally, no subprocess is spawned, and every tool and route handler returns a `code-runtime-unavailable` error. So if you are writing a project drop and you need to run code, the answer is `wasm` — declaring `mcp` to get a non-JS language will load the package and silently run none of it.
|
|
109
109
|
|
|
110
|
-
**If you need an existing MCP server, do not reach for this runtime at all — but check WHERE that server runs before you plan around a connector either.** Declare an `{ "type": "mcp" }` **connector** (`connectors[]` — a different field and a different discriminator) when the server is reachable **over HTTP**: give it a `url`, and once connected it is dialed into the agent's MCP session with zero code and zero schema of yours. **A local stdio server (`command`) is not dialed in-host at any tier** — the transport factory refuses stdio and the session factory skips the assignment with a warning, so only `url` servers are reached. Two consequences worth stating plainly: a `"type": "mcp"` connector that omits `transport` **defaults to `stdio`**, i.e. to the refused one, so name `transport` explicitly for an HTTP server; and a **local** non-JS server has no working route below
|
|
110
|
+
**If you need an existing MCP server, do not reach for this runtime at all — but check WHERE that server runs before you plan around a connector either.** Declare an `{ "type": "mcp" }` **connector** (`connectors[]` — a different field and a different discriminator) when the server is reachable **over HTTP**: give it a `url`, and once connected it is dialed into the agent's MCP session with zero code and zero schema of yours. **A local stdio server (`command`) is not dialed in-host at any tier** — the transport factory refuses stdio and the session factory skips the assignment with a warning, so only `url` servers are reached. Two consequences worth stating plainly: a `"type": "mcp"` connector that omits `transport` **defaults to `stdio`**, i.e. to the refused one, so name `transport` explicitly for an HTTP server; and a **local** non-JS server has no working route below native today, by this path or by `runtime.type: "mcp"`. The intended shape for that case is a managed sidecar, which does not exist yet.
|
|
111
111
|
|
|
112
|
-
`runtime.binding: "embedded"` is the one true hard reject — a non-
|
|
112
|
+
`runtime.binding: "embedded"` is the one true hard reject — a non-native package declaring it is marked `error` with `embedded binding requires native trust`; nothing registers.
|
|
113
113
|
|
|
114
114
|
**`runtime.skillScripts`** is `host | wasm-only | none`. An untrusted manifest declaring anything other than `"none"` fails validation (omitting it is also fine). Beyond that declaration-time check the value is **advertisement**: rendered as a tag in the package overview, enforcing nothing at runtime — do not plan around it blocking a spawn. Separately, `${SKILL_DIR}` resolves to a sentinel string only when a skill has **no host-side directory at all** (a source-contributed skill whose connector gives no container path); installed packages and project drops both resolve a real directory.
|
|
115
115
|
|
|
@@ -150,7 +150,7 @@ The three differ on two axes — LANGUAGE and CONFINEMENT — and only one of th
|
|
|
150
150
|
|
|
151
151
|
**`meta.families`** groups tools for UI and feature gating. **`meta.distribution`** has exactly four keys — `installRoot`, `gitRepository`, `gitRef`, `npm`; no `homepage`, `repository` or `bugs` key exists there.
|
|
152
152
|
|
|
153
|
-
**`source.kind`** records provenance — thirteen values: `neuralis`, `local-dir`, `mounted-dir`, `git`, `npm`, `archive`, `mcp-server`, plus the imported-ecosystem kinds `claude-skill`, `cursor-skill`, `gemini-extension`, `openclaw-plugin`, `openai-app`, `m365-agent`. Two rules bite: `git` **requires** `meta.distribution.gitRepository` or validation fails; `neuralis` is the
|
|
153
|
+
**`source.kind`** records provenance — thirteen values: `neuralis`, `local-dir`, `mounted-dir`, `git`, `npm`, `archive`, `mcp-server`, plus the imported-ecosystem kinds `claude-skill`, `cursor-skill`, `gemini-extension`, `openclaw-plugin`, `openai-app`, `m365-agent`. Two rules bite: `git` **requires** `meta.distribution.gitRepository` or validation fails; `neuralis` is never authored: the host stamps it — with `native` trust — on every package of its install slots (its own dependencies and the packages installed while it runs), and only that stamped pair lets a package's code be imported; a manifest that declares it is ignored (the validator warns), and a project drop can never reach it.
|
|
154
154
|
|
|
155
155
|
**Not in this contract — do not invent them:** no `category` enum, no curated keyword vocabulary beyond free-form `tags`, no `engines`/compatibility field, no manifest-level deprecation or yank key (`version` is metadata, not an update trigger — pulling a published version is a registry-side operation over the signed revocation feed, never a field you declare here).
|
|
156
156
|
|
|
@@ -169,13 +169,13 @@ Each of `tools`, `prompts`, `resources` takes `none | selected | all`; `selected
|
|
|
169
169
|
|
|
170
170
|
### A tool name is global: a collision is SHADOWED, not renamed
|
|
171
171
|
|
|
172
|
-
A tool name is one key for the whole deployment, so two packages — or a package and one of the platform's own tools, or an MCP server — can claim the same one. **Nothing is renamed.** Each agent answers the name with ONE claimant, chosen by rule, never by load order: the **
|
|
172
|
+
A tool name is one key for the whole deployment, so two packages — or a package and one of the platform's own tools, or an MCP server — can claim the same one. **Nothing is renamed.** Each agent answers the name with ONE claimant, chosen by rule, never by load order: the **native** claimant wins if there is one (the platform's own tools included), otherwise the lexically-smallest `packageId`, and any package before an MCP server. A claimant the caller cannot use — its package switched off for that agent, out of scope, or its tool feature-gated for the caller — drops out BEFORE the rule, so it never takes the name from anyone. The losing package keeps every one of its OTHER tools.
|
|
173
173
|
|
|
174
174
|
> **Symptom:** a call to your tool answers from another package. The package is healthy; the NAME is contested. An owner can pick your package for that name per agent in Tool Access, but by default the rule decides — rename your tool so nobody has to choose.
|
|
175
175
|
|
|
176
176
|
Where to look: the boot log carries a `Namespace collisions detected` line naming the owner and the shadowed package ids, and `GET tools/catalog` returns a `contestedTools` row (`{name, owner, claimants, preferred?}`) for each name contested for that agent.
|
|
177
177
|
|
|
178
|
-
So **pick a name nobody else will pick**. Prefix by domain, not by convenience — `acme_release_status`, not `status`. The rule is the ONLY protection, and it applies to every install class alike: the platform's own packages, an admin's `neuralis pkg add`'ed dependency and a project `_packages/` drop all fight for the same key. Trust decides who WINS the fight, never whether there is one — a host dependency is stamped `
|
|
178
|
+
So **pick a name nobody else will pick**. Prefix by domain, not by convenience — `acme_release_status`, not `status`. The rule is the ONLY protection, and it applies to every install class alike: the platform's own packages, an admin's `neuralis pkg add`'ed dependency and a project `_packages/` drop all fight for the same key. Trust decides who WINS the fight, never whether there is one — a host dependency is stamped `native` by the host regardless of its scope, so `@acme/*` next to `@neuralis/*` is a lexical tie-break, not a rescue. Nothing anywhere refuses to start over a collision: a taken name shadows, it never takes the deployment down.
|
|
179
179
|
|
|
180
180
|
## `dataLayout` — say where you keep your files
|
|
181
181
|
|
|
@@ -187,9 +187,9 @@ If your package writes under its own `data://` zone, declare the first-level dir
|
|
|
187
187
|
|
|
188
188
|
`"machineWritten": [{ "path": "*/stats/*.json", "class": "metrics" }]` (inside `dataLayout`) names the files your package writes on its own — never rendered into the prompt. `path` is a glob relative to your zone (`*` one segment, `**` any depth; a leading `/`, an empty or `..` segment, or any character outside `[A-Za-z0-9._*-]` rejects the manifest); `class` is `metrics` (numbers only), `log` or `runtime-text` (runtime state a person may search for). A NEW project's `data` source leaves `metrics` files out of its index from the start; existing projects keep their settings. Declarations from untrusted packages are ignored.
|
|
189
189
|
|
|
190
|
-
**The rest of the block is owned elsewhere:** `sources[]` / `connectors[]` / `uriPolicies` → `connectors-and-uri-policies.md` (a `uriPolicies` pattern may name only `packages://<self>/…` and `data://<self>/…`; a foreign namespace rejects the whole manifest — and a `connectors[]` entry registers into exactly ONE project partition, or into none at all when the package is neither
|
|
190
|
+
**The rest of the block is owned elsewhere:** `sources[]` / `connectors[]` / `uriPolicies` → `connectors-and-uri-policies.md` (a `uriPolicies` pattern may name only `packages://<self>/…` and `data://<self>/…`; a foreign namespace rejects the whole manifest — and a `connectors[]` entry registers into exactly ONE project partition, or into none at all when the package is neither native nor owned by a resolvable project), `credentials[]` / `configSettings[]` → `config-and-credentials.md`, `app.surfaces[]` → `surfaces-and-design.md`, `team[]` / workflows → `team-and-workflows.md` (note that `team[]` is VALIDATED fail-closed at load: a bad slug or a template path that leaves the package rejects the whole manifest).
|
|
191
191
|
|
|
192
|
-
## `events[]` — notifications from your package (
|
|
192
|
+
## `events[]` — notifications from your package (native only)
|
|
193
193
|
|
|
194
194
|
A package the host installs as a dependency can declare the moments a person should hear about — a run finished, a sync failed. The platform delivers them: a badge on your dock entry, a row in the user's inbox, per-person mute and follow. You build none of that UI. Any other install class has the field dropped at load with a warning.
|
|
195
195
|
|