@neuralis/brain-core 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +41 -40
  2. package/app/README.md +3 -3
  3. package/app/filesystem/FilesystemHost.tsx +7 -0
  4. package/app/filesystem/README.md +1 -1
  5. package/app/filesystem/api/index.ts +4 -4
  6. package/app/filesystem/hooks/README.md +1 -1
  7. package/app/filesystem/hooks/useFilesystemSSE.ts +41 -1
  8. package/app/filesystem/host/README.md +2 -2
  9. package/app/filesystem/host/buildFilesystemHostValue.ts +9 -2
  10. package/app/filesystem/lib/sourceKindForm.ts +109 -5
  11. package/app/filesystem/store/filesystemStore.ts +13 -3
  12. package/app/filesystem/ui/DiscoverDock.tsx +5 -1
  13. package/app/filesystem/ui/FileTree.tsx +34 -8
  14. package/app/filesystem/ui/FilesystemWidget.tsx +10 -2
  15. package/app/filesystem/ui/GitControlPanel.tsx +2 -2
  16. package/app/filesystem/ui/PendingChangesPanel.tsx +1 -1
  17. package/app/filesystem/ui/README.md +14 -13
  18. package/app/filesystem/ui/SourcesPanel.tsx +124 -24
  19. package/app/filesystem/ui/VectorHealthPanel.tsx +2 -2
  20. package/dist/app/host.js +41 -37
  21. package/dist/src/channels/filesystem.d.ts +1 -1
  22. package/dist/src/channels/filesystem.js +1 -1
  23. package/dist/src/domain/mime.d.ts +3 -3
  24. package/dist/src/domain/mime.js +3 -3
  25. package/dist/src/domain/scopeAccessCtx.d.ts +2 -2
  26. package/dist/src/domain/scopeAccessCtx.js +2 -2
  27. package/dist/src/domain/types.d.ts +8 -1
  28. package/dist/src/domain/types.d.ts.map +1 -1
  29. package/dist/src/events/pending.d.ts +1 -1
  30. package/dist/src/events/pending.js +1 -1
  31. package/dist/src/git/sourceGitControl.d.ts +2 -2
  32. package/dist/src/git/sourceGitControl.js +3 -3
  33. package/dist/src/lifecycle.d.ts +1 -1
  34. package/dist/src/routes/approve.d.ts +1 -1
  35. package/dist/src/routes/approve.js +1 -1
  36. package/dist/src/routes/events.d.ts +1 -1
  37. package/dist/src/routes/events.js +1 -1
  38. package/dist/src/routes/git.d.ts +7 -7
  39. package/dist/src/routes/git.js +18 -18
  40. package/dist/src/routes/health.d.ts +6 -6
  41. package/dist/src/routes/health.js +12 -12
  42. package/dist/src/routes/helpers/sourceNotConfigured.d.ts +1 -1
  43. package/dist/src/routes/helpers/sourceNotConfigured.js +1 -1
  44. package/dist/src/routes/helpers.d.ts +1 -1
  45. package/dist/src/routes/helpers.js +1 -1
  46. package/dist/src/routes/list.d.ts +1 -1
  47. package/dist/src/routes/list.js +1 -1
  48. package/dist/src/routes/pending.d.ts +4 -4
  49. package/dist/src/routes/pending.js +9 -9
  50. package/dist/src/routes/policies.d.ts +4 -4
  51. package/dist/src/routes/policies.d.ts.map +1 -1
  52. package/dist/src/routes/policies.js +11 -11
  53. package/dist/src/routes/policies.js.map +1 -1
  54. package/dist/src/routes/raw.d.ts +1 -1
  55. package/dist/src/routes/raw.js +1 -1
  56. package/dist/src/routes/read.d.ts +1 -1
  57. package/dist/src/routes/read.js +1 -1
  58. package/dist/src/routes/search.d.ts +1 -1
  59. package/dist/src/routes/search.js +1 -1
  60. package/dist/src/routes/sources.d.ts +20 -5
  61. package/dist/src/routes/sources.d.ts.map +1 -1
  62. package/dist/src/routes/sources.js +118 -118
  63. package/dist/src/routes/sources.js.map +1 -1
  64. package/dist/src/routes/upload.d.ts +1 -1
  65. package/dist/src/routes/upload.js +1 -1
  66. package/dist/src/routes/write.d.ts +2 -2
  67. package/dist/src/routes/write.js +2 -2
  68. package/dist/src/services/BridgeService.d.ts +7 -1
  69. package/dist/src/services/BridgeService.d.ts.map +1 -1
  70. package/dist/src/services/BridgeService.js +15 -3
  71. package/dist/src/services/BridgeService.js.map +1 -1
  72. package/dist/src/services/FilesystemService.d.ts +1 -1
  73. package/dist/src/services/FilesystemService.js +2 -2
  74. package/dist/src/services/declaredSources.d.ts +9 -3
  75. package/dist/src/services/declaredSources.d.ts.map +1 -1
  76. package/dist/src/services/declaredSources.js +2 -1
  77. package/dist/src/services/declaredSources.js.map +1 -1
  78. package/dist/src/tools/execCtx.d.ts +2 -2
  79. package/dist/src/tools/execCtx.js +2 -2
  80. package/dist/src/tools/fs_read.d.ts.map +1 -1
  81. package/dist/src/tools/fs_read.js +5 -0
  82. package/dist/src/tools/fs_read.js.map +1 -1
  83. package/dist/src/usecases/embeddingBacklog.js +1 -1
  84. package/dist/src/usecases/embeddingBacklog.js.map +1 -1
  85. package/dist/src/usecases/readFiles.d.ts.map +1 -1
  86. package/dist/src/usecases/readFiles.js +84 -1
  87. package/dist/src/usecases/readFiles.js.map +1 -1
  88. package/dist/src/usecases/syncPointWrites.d.ts +2 -0
  89. package/dist/src/usecases/syncPointWrites.d.ts.map +1 -1
  90. package/dist/src/usecases/syncPointWrites.js +5 -1
  91. package/dist/src/usecases/syncPointWrites.js.map +1 -1
  92. package/dist/src/usecases/vectorMaintenance.js +1 -1
  93. package/dist/src/usecases/vectorMaintenance.js.map +1 -1
  94. package/dist/src/usecases/write/content.js +1 -1
  95. package/dist/tools/fs_list.json +1 -1
  96. package/dist/tools/fs_read.json +1 -1
  97. package/dist/tools/fs_search.json +1 -1
  98. package/dist/tools/fs_write.json +1 -1
  99. package/instructions/brain-model.md +1 -1
  100. package/package.json +70 -63
  101. package/rules/brain-rules.md +2 -2
  102. package/skills/brain-start/SKILL.md +1 -1
  103. package/skills/connect-business-data/SKILL.md +1 -1
  104. package/skills/create-package/SKILL.md +8 -8
  105. package/skills/create-package/references/connectors-and-uri-policies.md +7 -2
  106. package/skills/create-package/references/runtime-and-build.md +1 -1
  107. package/skills/create-package/references/skills-and-context.md +1 -1
  108. package/skills/create-package/references/test-and-ship.md +4 -4
  109. package/skills/create-package/scripts/check-package.sh +1 -1
  110. package/skills/git/SKILL.md +23 -23
  111. package/skills/manage-files/SKILL.md +13 -13
  112. package/skills/manage-files/scripts/upload.sh +1 -1
  113. package/skills/manage-sources/SKILL.md +55 -54
  114. package/skills/manage-sources/scripts/reembed.sh +1 -1
  115. package/skills/manage-uri-policy/SKILL.md +9 -9
  116. package/skills/organize/SKILL.md +1 -1
  117. package/skills/sync/SKILL.md +2 -2
  118. package/tools/fs_list.json +1 -1
  119. package/tools/fs_read.json +1 -1
  120. package/tools/fs_search.json +1 -1
  121. package/tools/fs_write.json +1 -1
  122. package/workflows/sources-digest.json +1 -1
  123. package/docs/drive-overview.md +0 -59
@@ -2,7 +2,7 @@
2
2
  name: git
3
3
  description: "Operate git on a git-backed source through governed routes: inspect status, diff, history, and outgoing changes; stage, discard, commit, branch, switch, fetch, pull, or push. Use for repository work; choose governed git by default, raw CLI for allowed local inspection, and GitHub tools for remote collaboration."
4
4
  allowed-tools: execute
5
- requiredFeatures: [drive.read]
5
+ requiredFeatures: [files.read]
6
6
  ---
7
7
 
8
8
  # Git
@@ -10,7 +10,7 @@ requiredFeatures: [drive.read]
10
10
  Drive git on a **git-backed source** (any `local`-kind source that is a git checkout)
11
11
  through brain-core's governed git routes. These are the **same routes the Git Control
12
12
  panel drives**, so an agent gets exactly the rights a human member has: gated by
13
- `drive.read` / `drive.write` + the source's uri-policy, with a **server-side snapshot
13
+ `files.read` / `files.write` + the source's uri-policy, with a **server-side snapshot
14
14
  before every destructive op** and **credential-safe remotes** (the push/pull token is
15
15
  resolved server-side and never touches the agent shell).
16
16
 
@@ -83,25 +83,25 @@ unreadable; never write "no changes" into a report you cannot back.
83
83
 
84
84
  | Action | Method | Route | Key params | Gate |
85
85
  |---|---|---|---|---|
86
- | Whole-repo change-set + branch + ahead/behind | GET | `status` | `source`,`repo?` | `drive.read` + uri-policy `read` (root) |
87
- | Local branch list | GET | `branch` | `source`,`repo?` | `drive.read` + `read` (root) |
88
- | Per-file unified diff | GET | `diff` | `source`,`path` **(required)**; optionally one of `staged=1` \| `commit=<sha>` \| `base=<sha>&head=<sha>` (omit all three for the unstaged working-tree diff) | `drive.read` + `read` (per-path) |
89
- | Blob content at a rev | GET | `show` | `source`,`path`,`rev=index\|<sha>` | `drive.read` + `read` (per-path) |
90
- | Commit-DAG page (+ `outgoing[]`) | GET | `log` | `source`,`maxCount?`,`skip?`,`ref?` | `drive.read` + `read` (root) |
91
- | Per-commit `+/-` totals for a log page | GET | `log-stats` | `source`,`maxCount?`,`skip?`,`ref?` | `drive.read` + `read` (root) |
92
- | Files a commit changed | GET | `commit` | `source`,`sha=<sha>` | `drive.read` + `read` (root) |
93
- | Committed-but-not-pushed files | GET | `outgoing` | `source` | `drive.read` + `read` (root) |
94
- | In-source repo picker — **and the plane-liveness test: empty `repos` ⇒ every root-gated read fails soft** | GET | `repos` | `source` | `drive.read` + `read` (root) |
95
- | Stage whole files or a hunk | POST | `stage` | `source`,`paths:[…]` **or** `hunk:"<patch>"` | `drive.write` + `write` (per-path) |
96
- | Unstage whole files or a hunk | POST | `unstage` | `source`,`paths:[…]` **or** `hunk` | `drive.write` + `write` (per-path) |
97
- | Discard working-tree changes (**destructive** → returns `rescue`) | POST | `discard` | `source`,`paths:[…]` | `drive.write` + `write` (per-path) |
98
- | Create a commit from the index | POST | `commit` | `source`,`message`,`amend?` | `drive.write` + `write` (root) |
99
- | Create / delete a branch (delete **destructive** → `rescue`) | POST | `branch` | `source`,`action:"create"\|"delete"`,`name`,`startPoint?`,`force?` | `drive.write` + `write` (root) |
100
- | Switch branch (plain, refuses to clobber → 409) | POST | `checkout` | `source`,`ref` | `drive.write` + `write` (root) |
101
- | **Undo** a `discard` / `branch` delete from its `rescue` carrier | POST | `restore` | `source`,`rescue:{kind:"stash"\|"branch",ref,name?}` | `drive.write` + `write` (root) |
102
- | Fetch from the connected remote | POST | `fetch` | `source` | `drive.write` + uri-policy **`exec`** + connected remote |
103
- | Pull (fetch + fast-forward-only merge) | POST | `pull` | `source` | `drive.write` + `exec` + `write` + connected remote |
104
- | Push `HEAD` (no force) | POST | `push` | `source` | `drive.write` + `exec` + connected remote |
86
+ | Whole-repo change-set + branch + ahead/behind | GET | `status` | `source`,`repo?` | `files.read` + uri-policy `read` (root) |
87
+ | Local branch list | GET | `branch` | `source`,`repo?` | `files.read` + `read` (root) |
88
+ | Per-file unified diff | GET | `diff` | `source`,`path` **(required)**; optionally one of `staged=1` \| `commit=<sha>` \| `base=<sha>&head=<sha>` (omit all three for the unstaged working-tree diff) | `files.read` + `read` (per-path) |
89
+ | Blob content at a rev | GET | `show` | `source`,`path`,`rev=index\|<sha>` | `files.read` + `read` (per-path) |
90
+ | Commit-DAG page (+ `outgoing[]`) | GET | `log` | `source`,`maxCount?`,`skip?`,`ref?` | `files.read` + `read` (root) |
91
+ | Per-commit `+/-` totals for a log page | GET | `log-stats` | `source`,`maxCount?`,`skip?`,`ref?` | `files.read` + `read` (root) |
92
+ | Files a commit changed | GET | `commit` | `source`,`sha=<sha>` | `files.read` + `read` (root) |
93
+ | Committed-but-not-pushed files | GET | `outgoing` | `source` | `files.read` + `read` (root) |
94
+ | In-source repo picker — **and the plane-liveness test: empty `repos` ⇒ every root-gated read fails soft** | GET | `repos` | `source` | `files.read` + `read` (root) |
95
+ | Stage whole files or a hunk | POST | `stage` | `source`,`paths:[…]` **or** `hunk:"<patch>"` | `files.write` + `write` (per-path) |
96
+ | Unstage whole files or a hunk | POST | `unstage` | `source`,`paths:[…]` **or** `hunk` | `files.write` + `write` (per-path) |
97
+ | Discard working-tree changes (**destructive** → returns `rescue`) | POST | `discard` | `source`,`paths:[…]` | `files.write` + `write` (per-path) |
98
+ | Create a commit from the index | POST | `commit` | `source`,`message`,`amend?` | `files.write` + `write` (root) |
99
+ | Create / delete a branch (delete **destructive** → `rescue`) | POST | `branch` | `source`,`action:"create"\|"delete"`,`name`,`startPoint?`,`force?` | `files.write` + `write` (root) |
100
+ | Switch branch (plain, refuses to clobber → 409) | POST | `checkout` | `source`,`ref` | `files.write` + `write` (root) |
101
+ | **Undo** a `discard` / `branch` delete from its `rescue` carrier | POST | `restore` | `source`,`rescue:{kind:"stash"\|"branch",ref,name?}` | `files.write` + `write` (root) |
102
+ | Fetch from the connected remote | POST | `fetch` | `source` | `files.write` + uri-policy **`exec`** + connected remote |
103
+ | Pull (fetch + fast-forward-only merge) | POST | `pull` | `source` | `files.write` + `exec` + `write` + connected remote |
104
+ | Push `HEAD` (no force) | POST | `push` | `source` | `files.write` + `exec` + connected remote |
105
105
 
106
106
  Notes:
107
107
  - `GET commit` (what a commit changed) and `POST commit` (create a commit) are **different**
@@ -111,7 +111,7 @@ Notes:
111
111
  only (never paths), and read-denied paths are excluded from the totals. Use it instead of
112
112
  fetching diffs to count lines.
113
113
  - The three capability tiers are gated **independently server-side**, regardless of this skill's
114
- `requiredFeatures`: read routes need `drive.read`, write routes additionally need `drive.write`
114
+ `requiredFeatures`: read routes need `files.read`, write routes additionally need `files.write`
115
115
  (a read-only caller sees a **403** from any POST), and the remote routes additionally need
116
116
  uri-policy **`exec`** on the source root (`exec` is off by default → a **403** whose body
117
117
  carries a grant-exec affordance) **plus a connected remote** (409 `not_connected` /
@@ -120,7 +120,7 @@ Notes:
120
120
  return a typed `rescue` carrier. **Undo it through the governed `restore` route** — echo the
121
121
  carrier straight back: `POST restore` with `{"source":"…","rescue":{"kind":"stash","ref":"<sha>"}}`
122
122
  for discarded content, `{"kind":"branch","ref":"<anchor>","name":"<branch>"}` for a deleted
123
- branch. Same gate as any other write (`drive.write` + `write` on the root — no `exec`, no new
123
+ branch. Same gate as any other write (`files.write` + `write` on the root — no `exec`, no new
124
124
  capability), and the restore itself snapshots first. Do **not** reach for raw-shell
125
125
  `git stash apply` / `git branch` instead: Plane C has no snapshot, so a failed recovery there is
126
126
  unrecoverable. Surface the `rescue` to the user either way — a carrier you never mention is a
@@ -1,5 +1,5 @@
1
1
  ---
2
- requiredFeatures: [drive.write]
2
+ requiredFeatures: [files.write]
3
3
  name: manage-files
4
4
  description: "Perform bulk or route-level filesystem operations—list, search, read, raw, write (every verb), upload, and review approval—when fs_* calls are insufficient or an approval flow is involved. Use source URIs and preserve policy/scope; prefer direct fs_* for ordinary small file work."
5
5
  allowed-tools: execute
@@ -18,21 +18,21 @@ on your own machine); `write` and `upload` go through their scripts.
18
18
 
19
19
  | Action | Method | Path (`@neuralis/brain-core/…`) | Feature gate |
20
20
  |---|---|---|---|
21
- | List files / folders at a URI | POST | `list` | `drive.read` |
22
- | Search vector index | POST | `search` | `drive.search` |
23
- | Read multiple files | POST | `read` | `drive.read` |
24
- | Raw (un-summarized) read | GET | `raw` | `drive.read` |
25
- | Write — every verb (create / overwrite / edit / insert / lines / fields / move / copy / mkdir / revert / delete) | POST | `write` — `scripts/write.sh` | `drive.write` |
26
- | Upload a payload (multipart/form-data) | POST | `upload` — `scripts/upload.sh` | `drive.write` |
27
- | Approve a pending change | POST | `approve` | `drive.write` |
28
- | List pending changes (project-wide) | GET | `pending` | `drive.read` |
21
+ | List files / folders at a URI | POST | `list` | `files.read` |
22
+ | Search vector index | POST | `search` | `files.search` |
23
+ | Read multiple files | POST | `read` | `files.read` |
24
+ | Raw (un-summarized) read | GET | `raw` | `files.read` |
25
+ | Write — every verb (create / overwrite / edit / insert / lines / fields / move / copy / mkdir / revert / delete) | POST | `write` — `scripts/write.sh` | `files.write` |
26
+ | Upload a payload (multipart/form-data) | POST | `upload` — `scripts/upload.sh` | `files.write` |
27
+ | Approve a pending change | POST | `approve` | `files.write` |
28
+ | List pending changes (project-wide) | GET | `pending` | `files.read` |
29
29
 
30
30
  Per-route feature gates are enforced server-side by the RouteDispatcher against the
31
31
  caller's real `grantedFeatures`, independently of this skill's `requiredFeatures`
32
- frontmatter — `/list`, `/read`, `/raw` and `GET /pending` need `drive.read`; `/search` needs
33
- `drive.search`; `/write`, `/upload`, `/approve` and the mutating `/pending`
34
- verbs (`revert`, `discard`, `dismiss`, `discard-orphans`) need `drive.write`. A caller who holds
35
- `drive.write` (enough to see and activate this skill) but NOT `drive.search` gets a
32
+ frontmatter — `/list`, `/read`, `/raw` and `GET /pending` need `files.read`; `/search` needs
33
+ `files.search`; `/write`, `/upload`, `/approve` and the mutating `/pending`
34
+ verbs (`revert`, `discard`, `dismiss`, `discard-orphans`) need `files.write`. A caller who holds
35
+ `files.write` (enough to see and activate this skill) but NOT `files.search` gets a
36
36
  server-side **403** from `search` even though the other routes work.
37
37
 
38
38
  ## Bodies
@@ -3,7 +3,7 @@ set -euo pipefail
3
3
  # POST /upload REQUIRES multipart/form-data (NOT a JSON body): the handler reads the
4
4
  # form fields file (the binary/text payload), agentId, uri (optional), tags (optional,
5
5
  # comma-split). projectId is taken from the session ticket — passing a different one
6
- # is a 403. Requires the caller to hold the `drive.write` feature. agentId here is read
6
+ # is a 403. Requires the caller to hold the `files.write` feature. agentId here is read
7
7
  # from the form field.
8
8
  FILE_PATH="${FILE_PATH:?FILE_PATH is required (local path of the payload to upload)}"
9
9
  AGENT_ID="${AGENT_ID:?AGENT_ID is required (form field; the destination agent)}"
@@ -1,5 +1,5 @@
1
1
  ---
2
- requiredFeatures: [drive.read]
2
+ requiredFeatures: [files.read]
3
3
  name: manage-sources
4
4
  description: "Manage the full source lifecycle: survey freshness/index health, inspect kinds/schema, create/update/enable/disable/delete, browse, sync/cancel/reset/reindex, re-embed or clean a file/folder/source index, and diagnose vectors. Use when a source is stale, missing, misconfigured, offline, or needs lifecycle changes."
5
5
  allowed-tools: execute fs_list fs_read fs_search
@@ -24,7 +24,7 @@ Useful for:
24
24
  ## Read / survey mode (sources + freshness)
25
25
 
26
26
  To just **survey** the configured sources and their freshness (read-only, the
27
- `drive.read` floor — no mutation), use the `fs_*` tools rather than the routes:
27
+ `files.read` floor — no mutation), use the `fs_*` tools rather than the routes:
28
28
 
29
29
  1. Call `fs_list` with `include_counts: true` (no `uri` — root registry) to
30
30
  enumerate sources with `on_disk`, `indexed_count`, `unindexed`,
@@ -50,29 +50,29 @@ server-side source rows rather than the index-count survey.)
50
50
 
51
51
  ## Routes covered
52
52
 
53
- `drive.read` is the skill's floor; mutating + sync-lifecycle routes escalate
53
+ `files.read` is the skill's floor; mutating + sync-lifecycle routes escalate
54
54
  **in-handler** to a stronger feature and 403 an under-privileged caller (see
55
55
  **Feature gates** below). The `Feature` column is the gate actually enforced.
56
56
 
57
57
  | Action | Method | Path (`@neuralis/brain-core/…`) | Fields | Feature |
58
58
  |---|---|---|---|---|
59
- | List configured sources | GET | `sources` | `scope?`, `observed?` | `drive.read` |
60
- | Get one source's config | GET | `sources/<slug>` | | `drive.read` |
61
- | List registered kinds | GET | `sources/kinds` | | `drive.read` |
62
- | Get a kind's config schema | GET | `sources/kinds/<kind>/schema` | | `drive.read` |
63
- | Discoverable connectors (filesystem hints) | GET | `sources/discoverable` | | `drive.mount` |
64
- | Browse a filesystem path before adding it | GET | `sources/browse` | `path` | `drive.mount` |
65
- | Create a new source | POST | `sources` | body (below) | `drive.mount` |
66
- | Update an existing source | PATCH | `sources` | body (below) | `drive.mount` |
67
- | Delete a source | DELETE | `sources/<slug>[?purge=1]` | | `drive.mount` |
68
- | Enable / disable a source | POST | `sources/enabled` | `source`, `enabled` (`true`\|`false`\|`"auto"`) | `drive.mount` |
69
- | Trigger sync (202 + queue job snapshot) | POST | `sources/sync` | `source`, `agentId?` | `drive.sync` |
70
- | Cancel an in-flight sync | POST | `sources/cancel` | `source?` | `drive.sync` |
71
- | Job status | GET | `sources/sync-status` | `source?` | `drive.sync` |
72
- | Forget sync state (next tick re-walks; deletes nothing) | POST | `sources/reset` | `source` | `drive.sync` |
73
- | Rescan changes (full re-walk now; unchanged files keep their vectors; 202 + job) | POST | `sources/reindex` | `source`, `agentId?` | `drive.sync` |
74
- | Clean a file / folder / source index (estimate first) | POST | `sources/purge` | body (below) | `drive.mount` + `drive.sync` |
75
- | Catch up embedding debt; FORCE=1 re-embeds (estimate first) | POST | `sources/reindex` + `embeddingOnly` or `force` — run `bash ${SKILL_DIR}/scripts/reembed.sh` | env | `drive.sync` |
59
+ | List configured sources | GET | `sources` | `scope?`, `observed?` | `files.read` |
60
+ | Get one source's config | GET | `sources/<slug>` | | `files.read` |
61
+ | List registered kinds | GET | `sources/kinds` | | `files.read` |
62
+ | Get a kind's config schema | GET | `sources/kinds/<kind>/schema` | | `files.read` |
63
+ | Discoverable connectors (filesystem hints) | GET | `sources/discoverable` | | `sources.mount` |
64
+ | Browse a filesystem path before adding it | GET | `sources/browse` | `path` | `sources.mount` |
65
+ | Create a new source | POST | `sources` | body (below) | `sources.mount` |
66
+ | Update an existing source | PATCH | `sources` | body (below) | `sources.mount` |
67
+ | Delete a source | DELETE | `sources/<slug>[?purge=1]` | | `sources.mount` |
68
+ | Enable / disable a source | POST | `sources/enabled` | `source`, `enabled` (`true`\|`false`\|`"auto"`) | `sources.mount` |
69
+ | Trigger sync (202 + queue job snapshot) | POST | `sources/sync` | `source`, `agentId?` | `sources.sync` |
70
+ | Cancel an in-flight sync | POST | `sources/cancel` | `source?` | `sources.sync` |
71
+ | Job status | GET | `sources/sync-status` | `source?` | `sources.sync` |
72
+ | Forget sync state (next tick re-walks; deletes nothing) | POST | `sources/reset` | `source` | `sources.sync` |
73
+ | Rescan changes (full re-walk now; unchanged files keep their vectors; 202 + job) | POST | `sources/reindex` | `source`, `agentId?` | `sources.sync` |
74
+ | Clean a file / folder / source index (estimate first) | POST | `sources/purge` | body (below) | `sources.mount` + `sources.sync` |
75
+ | Catch up embedding debt; FORCE=1 re-embeds (estimate first) | POST | `sources/reindex` + `embeddingOnly` or `force` — run `bash ${SKILL_DIR}/scripts/reembed.sh` | env | `sources.sync` |
76
76
 
77
77
  > **`update` takes no `<slug>`.** PATCH targets the bare `sources` path; the
78
78
  > source to patch is the body `source` field (the handler ignores the path).
@@ -87,49 +87,50 @@ array** of source rows (NOT `{ sources: [...] }`). Pipe `jq '.[]'`, never
87
87
  `jq '.sources[]'` (that errors `Cannot index array with string "sources"`). Each
88
88
  element carries `slug`, `enabled`, `connection.kind`, `scope`, plus the enrichment
89
89
  fields above. `connection.config` is `{}` unless you could attach the source or
90
- read its root, and `sync.lastSyncResult.error` is a fixed text without `drive.sync`. `GET sources/<slug>` returns a single object, not an array.
90
+ read its root, and `sync.lastSyncResult.error` is a fixed text without `sources.sync`. `GET sources/<slug>` returns a single object, not an array.
91
91
 
92
92
  ## Feature gates
93
93
 
94
- The skill declares `drive.read`, which covers the source-config READ routes.
94
+ The skill declares `files.read`, which covers the source-config READ routes.
95
95
  Everything that mutates, syncs, or ENUMERATES THE HOST enforces a **stronger**
96
- feature server-side, beyond the `drive.read` floor — a caller holding only
97
- `drive.read` gets a `403`:
96
+ feature server-side, beyond the `files.read` floor — a caller holding only
97
+ `files.read` gets a `403`:
98
98
 
99
- - **`drive.mount`** — create, update, delete, enable/disable, browse and the
99
+ - **`sources.mount`** — create, update, delete, enable/disable, browse and the
100
100
  discoverable list. Browsing and the
101
101
  discoverable list are the steps that PRECEDE attaching, and they enumerate the
102
102
  host: you may browse exactly what you would be allowed to attach.
103
- - **`drive.mount.privileged`** — browsing the filesystem root or any
103
+ - **`sources.privileged`** — browsing the filesystem root or any
104
104
  protected host zone (the App Zone, the Neuralis tree), the same zones whose
105
105
  ATTACH needs it. A protected directory is also omitted from the listing of a
106
106
  parent you may browse, so an absent entry is not proof it does not exist.
107
- - **`drive.sync`** — sync, cancel, reset, reindex, `reembed.sh`, sync-status.
107
+ - **`sources.sync`** — sync, cancel, reset, reindex, `reembed.sh`, sync-status.
108
108
 
109
- The index purge requires both `drive.mount` and `drive.sync`, source-scope management authority and current READ visibility.
109
+ The index purge requires both `sources.mount` and `sources.sync`, source-scope management authority and current READ visibility.
110
110
 
111
111
  Create/update/delete/enable additionally enforce `canAccessScope(.., 'write')`
112
112
  on the target source's scope, and create validates the kind's scope rules.
113
113
 
114
114
  ### Privileged and host-plane sources
115
115
 
116
- Two escalations sit above `drive.mount`, neither granted below the `admin` tier (`admin` holds
117
- them through its enumerated default grants, `owner` through the `'*'` wildcard; both are
118
- grantable to any custom role):
116
+ One escalation sits above `sources.mount`, not granted below the `admin` tier (`admin` holds
117
+ it through its enumerated default grant, `owner` through the `'*'` wildcard; grantable to any
118
+ custom role):
119
119
 
120
- - **`drive.mount.privileged`** — attaching (or seeing) a source rooted in, over, or at a
120
+ - **`sources.privileged`** — attaching (or seeing) a source rooted in, over, or at a
121
121
  high-blast-radius zone: the platform App Zone, the Neuralis source tree, or the whole
122
122
  filesystem (`/`). Containment is checked in both directions on canonical paths, so a
123
123
  sub-path or an ancestor of a protected zone is caught too.
124
- - **`drive.mount.host`** — attaching or editing any source on the HOST plane (a connector
125
- kind of `host` / `host-*`, resolving on the operator's machine rather than in the
126
- container). **Both features are required together for a host source, at every root** —
127
- there is no unprivileged host root, so `/home/me/notes` is gated exactly like `/`.
128
124
 
129
- A host source is also bounded by an operator-owned ceiling the platform cannot widen: even
130
- a permissive source policy only reaches paths the operator listed. If a host read or write
131
- fails while the source policy allows it, report the ceiling as the limit — it is an
132
- operator change, not a policy edit.
125
+ A source on the HOST plane (a connector kind of `host` / `host-*`, on a paired device
126
+ rather than in the container) has one rule: **only that device's owner, holding
127
+ `device.own`, attaches or edits it** — at every root, and no role feature replaces it.
128
+ Anyone else gets 403, whatever they hold.
129
+
130
+ A host source is also bounded by the device's own allowlist, which the platform cannot
131
+ widen: even a permissive source policy only reaches paths the device's owner granted. If a
132
+ host read or write fails while the source policy allows it, report the allowlist as the
133
+ limit — the owner widens it with `neuralis device grant`, not a policy edit.
133
134
 
134
135
  Attaching a host source is not the same act as granting host command execution: reading
135
136
  files through `fs_*` and running commands there are separate grants.
@@ -199,7 +200,7 @@ to change. Every update example below does exactly that.
199
200
 
200
201
  **`syncExcludes` is a PREFERENCE; the uri policy is the security half. Do not
201
202
  confuse them.** A source's `sync.exclude` list is yours to edit — it is noise
202
- control (do not index `node_modules`), per source, managed through `drive.mount`.
203
+ control (do not index `node_modules`), per source, managed through `sources.mount`.
203
204
  It is NOT how you keep a secret out of the index. The immutable `floor:true`
204
205
  uri-policy rows are: a path whose floor denies `read` cannot be read by any
205
206
  caller AND is never newly embedded, because *what cannot be read cannot be
@@ -251,9 +252,9 @@ server-side gates apply regardless of what you send (`src/routes/sources.ts`):
251
252
  weaker gets `403 Setting recognizesPackages requires an owner/admin-effective
252
253
  role.` — quote that string verbatim when you report it. It names the required
253
254
  STRENGTH, not a role you have to be called. This is the SECOND gate on the
254
- route: `drive.mount` is checked first for the whole PATCH, so a caller without
255
+ route: `sources.mount` is checked first for the whole PATCH, so a caller without
255
256
  it never reaches this message and sees `403 Updating sources requires
256
- drive.mount.` instead. Read the two strings as different answers — a missing
257
+ sources.mount.` instead. Read the two strings as different answers — a missing
257
258
  feature grant versus insufficient role strength.
258
259
  - **Local-kind only** — setting it on a non-`local` connection returns `400`.
259
260
 
@@ -266,7 +267,7 @@ scope (a different run identity sees nothing — correct-by-design, not a load f
266
267
  # substitute a slug from the sources list. The effect is live — every matching .md under
267
268
  # it starts being advertised as a package contribution on the next sync — and it
268
269
  # is reversible only by resending the same body with `recognizesPackages:false`.
269
- # Needs drive.mount, then priority <= 2 (the admin anchor) or a '*' grant, and a
270
+ # Needs sources.mount, then priority <= 2 (the admin anchor) or a '*' grant, and a
270
271
  # local-kind source. The body carries the source's CURRENT permissions back —
271
272
  # PATCH replaces them:
272
273
  neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.source=="repo") | {source, permissions, recognizesPackages:true}' | neuralis request PATCH @neuralis/brain-core/sources --input -
@@ -305,11 +306,11 @@ neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.connection
305
306
  # The on-disk connector's id is `local-disk` but its kind is `local` — send `local`.
306
307
  neuralis request GET @neuralis/brain-core/sources/kinds --jq '.kinds[].kind'
307
308
  neuralis request GET @neuralis/brain-core/sources/kinds/local/schema
308
- neuralis request POST @neuralis/brain-core/sources/sync -f source=data # needs drive.sync
309
+ neuralis request POST @neuralis/brain-core/sources/sync -f source=data # needs sources.sync
309
310
  neuralis request GET @neuralis/brain-core/sources/sync-status -f source=data
310
311
  # `"auto"` = live only while the source's runtime runs; a boolean is typed with -F
311
312
  neuralis request POST @neuralis/brain-core/sources/enabled -f source=data -F enabled=true
312
- neuralis request GET @neuralis/brain-core/sources/browse -f path=/tmp # needs drive.mount
313
+ neuralis request GET @neuralis/brain-core/sources/browse -f path=/tmp # needs sources.mount
313
314
  ```
314
315
 
315
316
  ### Lifecycle walkthrough — create → update → delete
@@ -325,10 +326,10 @@ the `delete` on the last line would destroy the project's real source instead of
325
326
  the throwaway.
326
327
 
327
328
  ```bash
328
- # 1. Create (needs drive.mount). source + connection.kind + permissions.default.* required.
329
+ # 1. Create (needs sources.mount). source + connection.kind + permissions.default.* required.
329
330
  # The root does not have to exist yet — create records the coordinate, sync walks it.
330
331
  neuralis request POST @neuralis/brain-core/sources --input - <<<'{"source":"scratch-demo","connection":{"kind":"local","config":{"root":"/tmp/scratch-demo"}},"permissions":{"default":{"read":true,"write":true,"exec":false}}}'
331
- # 2. Update — NO SLUG; the body `source` field is the key (needs drive.mount).
332
+ # 2. Update — NO SLUG; the body `source` field is the key (needs sources.mount).
332
333
  # Sets the description shown in the agent <runtime_stack>. `permissions` is
333
334
  # REPLACED, so read the live object back and resend it unchanged, editing only
334
335
  # the field you meant to change — a hand-written {"default":…} body here would
@@ -344,8 +345,8 @@ neuralis request DELETE '@neuralis/brain-core/sources/scratch-demo?purge=1'
344
345
  ## Vector health (index diagnostics)
345
346
 
346
347
  The health route is SPLIT into a count-cheap path and a scan path (pattern `health/*`, feature
347
- `drive.read`) — call it with `neuralis request`. **The two
348
- read paths run on `drive.read`; the `gc` path does not** — it additionally requires `drive.write`
348
+ `files.read`) — call it with `neuralis request`. **The two
349
+ read paths run on `files.read`; the `gc` path does not** — it additionally requires `files.write`
349
350
  and is POST-only (see below). That covers its actions: `gc`, `repair-orphans` and `repair-pending`
350
351
  mutate, and `deduplicate` is read-only but rides the same gate — its rows enumerate other agents'
351
352
  `data://` paths.
@@ -362,14 +363,14 @@ mutate, and `deduplicate` is read-only but rides the same gate — its rows enum
362
363
  - **`POST …/brain-core/health/gc`** with `{action}` (`gc` / `repair-orphans` / `repair-pending` / `deduplicate`) —
363
364
  `gc`, `repair-orphans` and `repair-pending` MUTATE — run those only after a scan confirms a finding; `deduplicate`
364
365
  removes nothing (it reports groups) but is gated identically. **POST only** — a GET answers
365
- `405 Method GET not allowed`. It needs **`drive.write`** on top of the route's `drive.read`; a
366
- caller without it gets `403 {"error":"Missing feature: drive.write (vector health repair)"}`.
366
+ `405 Method GET not allowed`. It needs **`files.write`** on top of the route's `files.read`; a
367
+ caller without it gets `403 {"error":"Missing feature: files.write (vector health repair)"}`.
367
368
  That is a capability the caller lacks, not a broken call: report the finding and say that the
368
- sweep needs `drive.write` (manager tier and up), rather than retrying.
369
+ sweep needs `files.write` (manager tier and up), rather than retrying.
369
370
  `dryRun` DEFAULTS TO FALSE — pass `{"dryRun": true}` first when you want a preview. `repair-pending` processes one visible batch (default 50) and returns `scannedVisible`, `orphaned`, `attempted`, `discarded`, `refused`, `failed`, safe reason counts, `nextCursor`, `complete` and `partial`. Pass the returned `nextCursor` as `cursor` in the next POST only after checking the result; pause on partial/failure, retry explicitly, and restart on `restartRequired`. Each page reconstructs the complete projected inventory; the batch bounds mutations, not scan work. A terminal acknowledgement is not a newly discarded record.
370
371
  - **`GET …/brain-core/health/hot-uris`** → the files the index rewrote most in the last hour:
371
372
  `{windowMinutes, threshold, uris: [{uri, writes, points, lastWriteAt, hot}]}` (`writes` = file
372
- writes, `points` = index points incl. chunks). Same `drive.write` gate; already filtered to the
373
+ writes, `points` = index points incl. chunks). Same `files.write` gate; already filtered to the
373
374
  files you may read. Use it when indexing load is high or `deletedCount` keeps growing.
374
375
 
375
376
  `unindexed` / `stale_indexed` are NOT in the health route at all — get those per-source from
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
- # Requires drive.sync (403 otherwise). FORCE=1 re-embeds with the ACTIVE model; otherwise catches up durable embedding debt — a
3
+ # Requires sources.sync (403 otherwise). FORCE=1 re-embeds with the ACTIVE model; otherwise catches up durable embedding debt — a
4
4
  # file (URI), a folder's indexed files (FOLDER) or, with neither, the whole
5
5
  # source — even when nothing changed. Default = the ESTIMATE only (changes
6
6
  # nothing); CONFIRM=1 starts it (202 + job). Only files you may read count.
@@ -1,7 +1,7 @@
1
1
  ---
2
- requiredFeatures: [drive.policy]
2
+ requiredFeatures: [sources.policy]
3
3
  name: manage-uri-policy
4
- description: "Inspect and patch role-aware read, write, and execute URI policy for any source. Use when a legitimate path is denied or access must be narrowed; patching needs the drive.policy feature, and prefer the smallest explicit exception over broad defaults."
4
+ description: "Inspect and patch role-aware read, write, and execute URI policy for any source. Use when a legitimate path is denied or access must be narrowed; patching needs the sources.policy feature, and prefer the smallest explicit exception over broad defaults."
5
5
  allowed-tools: execute
6
6
  ---
7
7
 
@@ -100,24 +100,24 @@ package's seed.
100
100
 
101
101
  - **Two arms, both keyed on FEATURES — there is no role-name check on this
102
102
  route.** Reading (`GET policies/uri/...`) is
103
- the module feature `drive.read`, which every built-in role holds down to
103
+ the module feature `files.read`, which every built-in role holds down to
104
104
  `viewer`. Patching (`POST policies/uri`) escalates in-handler to
105
- `drive.policy` and otherwise returns
106
- `403 Missing feature: drive.policy (URI policy editing)`. `drive.policy` has
105
+ `sources.policy` and otherwise returns
106
+ `403 Missing feature: sources.policy (URI policy editing)`. `sources.policy` has
107
107
  no grant below the `admin` tier (enumerated for `admin`, `'*'` for `owner`)
108
108
  and is grantable to any custom role — so a custom role can hold it and a
109
109
  built-in one can lack it.
110
110
  - **Being able to SEE this skill is not the route gate.** Its
111
- `requiredFeatures: [drive.policy]` frontmatter hides the bundle from anyone
111
+ `requiredFeatures: [sources.policy]` frontmatter hides the bundle from anyone
112
112
  without that feature; that is the ADVERTISEMENT layer. The session ticket
113
113
  carries your real identity to the route, and there is no synthetic owner
114
114
  upgrade anywhere.
115
115
  - **Patching SOMEONE ELSE'S user- or agent-scoped source additionally needs scope
116
116
  WRITE.** The POST runs `canAccessScope(..., 'write')` on the owning scope, which
117
117
  passes unconditionally for a project-scoped source and for your OWN user/agent
118
- scope — so on the common path `drive.policy` is the whole answer. Only a
119
- CROSS-scope patch consults `filesystem.modifyScoped`; an
120
- `observeScoped`-but-not-`modifyScoped` holder gets
118
+ scope — so on the common path `sources.policy` is the whole answer. Only a
119
+ CROSS-scope patch consults `files.writeOthers`; an
120
+ `files.readOthers`-but-not-`files.writeOthers` holder gets
121
121
  `403 Forbidden for source scope` there.
122
122
  - **Manifest baselines are not edited by this skill.** Package
123
123
  manifests ship `permissions.uriPolicies` as the read-only baseline;
@@ -1,5 +1,5 @@
1
1
  ---
2
- requiredFeatures: [drive.write]
2
+ requiredFeatures: [files.write]
3
3
  name: organize
4
4
  description: "Analyze a workspace for duplicate, misplaced, stale, or poorly indexed material and design a safer information architecture. Use when asked to clean up or reorganize; inspect references and propose or preview moves before mutating shared files."
5
5
  allowed-tools: fs_search fs_write fs_list fs_read
@@ -1,5 +1,5 @@
1
1
  ---
2
- requiredFeatures: [drive.sync]
2
+ requiredFeatures: [sources.sync]
3
3
  name: sync
4
4
  description: "Run and verify brain-core delta synchronization for configured sources. Use when live connector content and the vector index may differ, files are stale or unindexed, or changes must become searchable; inspect completion and index state instead of trusting dispatch alone."
5
5
  allowed-tools: fs_list fs_read execute
@@ -12,7 +12,7 @@ Trigger a delta sync for the brain-core filesystem.
12
12
  ## Steps
13
13
 
14
14
  1. Use `fs_list` with no `uri` first to identify configured sources, scopes, current sync status, and recent errors.
15
- 2. Call the brain-core source sync route for the intended source. The route answers 202 + a queue job snapshot — the sync runs in the background. Explicit sync requires `drive.sync`; source create/update/delete uses `drive.mount`; file writes use `drive.write`.
15
+ 2. Call the brain-core source sync route for the intended source. The route answers 202 + a queue job snapshot — the sync runs in the background. Explicit sync requires `sources.sync`; source create/update/delete uses `sources.mount`; file writes use `files.write`.
16
16
  3. Poll `GET /sources/sync-status?source=<slug>` until the job finishes, then report the job `result` counts: `filesAdded`, `filesUpdated`, `filesRemoved`, `filesSkipped`, `filesMoved`, `chunksRemoved`, `chunksEmbedded` and `chunksSkipped` plus `embeddingDegraded` (safe, deduplicated embedding stop reasons). Payload indexing can succeed with missing/stale embeddings; report that debt separately. Read the two flags before interpreting completion. `cancelled: true` is not a failure, but the run stopped early: the counts are partial and a re-run converges. `truncated: true` means the walk stopped at `filesScanCap`, so files past the cap were never examined and no deletion or move was inferred — call that a partial pass, never a completed sync.
17
17
  4. If any errors occur, list them clearly with the affected source, scope, and file path.
18
18
  5. Distinguish live connector data, indexed payload and embedding freshness. Provider outage or disabled embedding preserves metadata/full-text indexing; semantic results may be old, or the response may fall back to filter search. Ordinary sync completion does not settle all embedding debt. Use `manage-sources` explicit debt catchup; terminal `paused` carries `result.embedding.pausedReason`, and Resume creates a new authorized job from durable debt.
@@ -73,7 +73,7 @@
73
73
  "transport": "embedded",
74
74
  "requires": {
75
75
  "features": [
76
- "drive.read"
76
+ "files.read"
77
77
  ]
78
78
  },
79
79
  "defaults": {
@@ -70,7 +70,7 @@
70
70
  "transport": "embedded",
71
71
  "requires": {
72
72
  "features": [
73
- "drive.read"
73
+ "files.read"
74
74
  ]
75
75
  },
76
76
  "defaults": {},
@@ -80,7 +80,7 @@
80
80
  "transport": "embedded",
81
81
  "requires": {
82
82
  "features": [
83
- "drive.search"
83
+ "files.search"
84
84
  ]
85
85
  },
86
86
  "defaults": {
@@ -226,7 +226,7 @@
226
226
  "transport": "embedded",
227
227
  "requires": {
228
228
  "features": [
229
- "drive.write"
229
+ "files.write"
230
230
  ]
231
231
  },
232
232
  "askOnKeys": [
@@ -27,5 +27,5 @@
27
27
  ],
28
28
  "defaultStateMode": "fresh",
29
29
  "delivery": { "mode": "none" },
30
- "requires": { "features": ["drive.search"] }
30
+ "requires": { "features": ["files.search"] }
31
31
  }
@@ -1,59 +0,0 @@
1
- ---
2
- id: drive-overview
3
- title: Drive Overview
4
- description: URI schemes, tool capabilities, and sync reality for the virtual filesystem
5
- ---
6
-
7
- ## URI Schemes
8
-
9
- | Scheme | Connector kind | Storage | Indexed | Example |
10
- |--------|---------|---------|---------|---------|
11
- | `brain://` | `brain` (builtin) | Qdrant vector DB (inline) | always | `brain://docs/note.md` |
12
- | `data://` | `local` (builtin) | Project data zone on disk + Qdrant | if configured & synced | `data://code/app.ts` |
13
- | `<slug>://` | `local` (user) | Any additional `local` mount, under its own slug (lower-case letters, digits and hyphens only — never a dot) + Qdrant | if configured & synced | `archive://old/x.md` |
14
- | `packages://` | `local` (builtin) | `_packages/` on disk + Qdrant | if configured & synced | `packages://my-pkg/tools/tool.json` |
15
- | `app://` | `local` (builtin, privileged mount) | Platform app zone (`~/.neuralis/app/`) | rarely synced | `app://config/sources/...` |
16
- | `neuralis://` | `local` (user, via `pnpm neuralis:mount add … --neuralis`) | The deployment's own `neuralis/` folder, live from the host (`scripts/`, `skills/`, `src/`, config — and `.env`) + Qdrant | if synced | `neuralis://scripts/mount.mts` |
17
- | `neuralis-skills://` | `local` (user, same overlay rooted at `<root>/skills`) | Just the shipped operator skills — the narrower default, offered first | if synced | `neuralis-skills://neuralis-operations/SKILL.md` |
18
- | `machine://` | `webtop` (`@neuralis/machine-core`) | Webtop sandbox | n/a | `machine://desktop/clipboard.txt` |
19
- | `<slug>://` | `host` (`@neuralis/agent-core`) | Operator's machine, OUTSIDE the container, via the operator-provisioned host broker | if configured & synced | `host-dev://repos/app/src/main.ts` |
20
-
21
- `os://<key>` is **not** a callable scheme — it is a decorative label
22
- rendered inside the system prompt's `<runtime_stack>` block for
23
- `NEURALIS_MOUNT_<KEY>` mounts. To address files inside a mount, use the
24
- `local`-kind source slug that was attached to that mount (e.g.
25
- `neuralis://` after `pnpm neuralis:mount add … --neuralis`).
26
-
27
- ## Tool Quick Reference
28
-
29
- | Tool | Purpose | Key Detail |
30
- |------|---------|------------|
31
- | `fs_search` | Find by meaning, keyword, metadata, or live grep | `query` = semantic / grep pattern / filter content-keyword (tokenized over indexed text in `filter` mode), `glob` = filename keyword, `search_mode: "filter"` = metadata only, `search_mode: "grep"` + `folder_uri` = ripgrep over the live connector (works even for unsynced subpaths; results stay scoped to `folder_uri`; uri-policy `read`-gated). |
32
- | `fs_read` | Read content (batch max 10) | URIs or UUIDs. `line_start`/`line_end` for large files. |
33
- | `fs_list` | Workspace overview + folder browse (unified) | Omit / empty / `/` → full root (`all://`) with source registry. Pass a real URI to scope. `recursive:false` = direct children only (fast). `include=folders\|files\|all`, `summary_chars>0` attaches previews (use on small scoped folders — identity, rules). `include_metadata:true` surfaces id/category/tags/timestamps in the markdown. `only_indexed:true` skips the live merge. |
34
- | `fs_write` | Create, edit or restructure — one tool, one call | The VERB is a KEY: `create` (never overwrites — a taken name lands beside as `name-2.ext`), `overwrite`, `edit[]` (targeted `old_string`→`new_string`, in order), `insert` (by line), `lines` (replace a range), `fields` (category/tags/metadata/pinned), `move`, `copy` (file or folder; the destination may be in another source), `mkdir` (not on `brain://`), `revert` (1-level undo), `delete` (a file, or a whole folder recursively). Content verbs compose in ONE write; structural verbs stand alone. Agent-runtime deletes require approval. |
35
-
36
- ## Indexed vs Live (connector-first contract)
37
-
38
- - **`brain://`** — Always indexed (content lives inline in Qdrant).
39
- - **`data://`, `packages://`, `neuralis://`, `app://` and any other `local`-kind slug** — Backed by a live `local`-kind connector; indexed mirror follows once sync has run.
40
- - `fs_read` / `fs_list` go connector-first, so they work even when the index is cold or Qdrant is unreachable.
41
- - Indexed searches require a warm index; payload and full-text indexing work without embeddings. Check `effective_mode`, `embedding_degraded` and row `embedding_status`: semantic requests can fall back to indexed text, and retained vectors can lag behind current content.
42
- - `fs_search` in `grep` mode bypasses the index entirely and greps the connector directly (ripgrep / git grep / grep). It is uri-policy `read`-gated — only paths the caller holds `read` policy on are grepped (a `read:false` subtree is silently absent; a fully-denied `folder_uri` → 403). It needs no `execute`/shell/`exec.unconfined` access: `drive.search` + `read` policy is enough, making it the uri-policy-gated counterpart to `execute`+grep.
43
- - **`machine://`** — Backed by `machine-core`'s `webtop` connector against a running webtop session; `'auto'` enabled-state resolves through the host-injected probe.
44
- - **`host`-kind slugs** — Backed by `agent-core`'s host connector, resolving on the operator's machine outside the container. It exists only where the operator provisioned the broker; attaching one needs `drive.mount.host` **and** `drive.mount.privileged`. Addressed by its own slug like any other source.
45
- - **`FilePresence`** per node: `brain` (vector-only), `synced` (index + connector agree), `unindexed` (on-disk but not indexed yet), `stale_indexed` (index has it, connector doesn't).
46
- - **Unmounted dirs** — Not addressable as a Neuralis URI; the agent can still touch them through the `execute` tool's shell pipeline when the runtime grants exec, but `fs_*` will reject the URI.
47
-
48
- ## Sources, Scope, and Access
49
-
50
- - Source slugs are URI schemes. Scoped clones use distinct schemes such as `local-alice://` or `machine-agent1://`; never assume every local source is named `data://`.
51
- - Built-in connector kinds come from package manifests: `local` is live disk, `brain` is Qdrant-backed internal memory, and other packages can contribute more `type: "source"` connectors through the same registry.
52
- - Source scopes are `project`, `user`, or `agent`. Project sources are visible to project members with the right feature grants; user/agent sources require ownership or scoped observation/modification features.
53
- - Feature gates: `drive.read` covers read/list/raw/events, the vector-health READS (stats and scan) and source metadata reads, `drive.search` covers indexed and grep search, `drive.write` covers create/modify/mkdir/copy/approve/upload, the mutating Pending Changes verbs and the vector-health `gc` sweep (`POST health/gc` — POST-only, `dryRun` defaults to false), `drive.mount` covers source create/update/delete/enable **and the two host-enumeration reads that precede an attach** (`sources/browse`, `sources/discoverable`), and `drive.sync` gates explicit sync plus cancel, reset, reindex and sync-status. Three features escalate above those and none is granted below the admin tier: `drive.policy` edits a source's URI policy, and `drive.mount.privileged` together with `drive.mount.host` are both required to attach a source on a high-blast-radius or host-plane root (and `drive.mount.privileged` alone gates BROWSING the filesystem root or a high-blast-radius zone). Reaching another identity's user- or agent-scoped source additionally needs `filesystem.observeScoped` (read) or `filesystem.modifyScoped` (write). The package declares two more features that gate affordances rather than paths: `packages.author` (the Packages panel authoring launcher) and `packages.registry` (the marketplace skill) — neither widens filesystem access.
54
-
55
- ## Recovery and Health
56
-
57
- - Every write snapshots `version.baseline`; `fs_write {revert:true}` is the one-level recovery path.
58
- - A certified embedding generation locks its model and dimension. Existing collections without that proof retain unknown vectors as metadata indexes. Typed provider unavailability leaves payload indexing operational; invalid lock/schema records still fail closed. Changing an active generation requires an explicit rebuild rather than guessing vector compatibility.
59
- - Tool usage/accounting belongs under `_meta.neuralis.usage`; model-visible results stay in `content` and `structuredContent`.