fuli-context 0.2.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.
Files changed (220) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +178 -0
  3. package/compose.graphiti.yml +86 -0
  4. package/dist/web/assets/ConnectionsPage-CY6H_mJJ.js +1 -0
  5. package/dist/web/assets/KnowledgeInspector-BSpz5Sfm.js +1 -0
  6. package/dist/web/assets/KnowledgeInspector-CHbB_0rC.css +1 -0
  7. package/dist/web/assets/KnowledgeOrganizerPage-BlEvhPrv.css +1 -0
  8. package/dist/web/assets/KnowledgeOrganizerPage-CvjGPlUc.js +1 -0
  9. package/dist/web/assets/KnowledgePage-Khuo3cNs.js +1 -0
  10. package/dist/web/assets/KnowledgeWorkspace-DVZusvem.js +4 -0
  11. package/dist/web/assets/OverviewPage-DC4C4Fhn.js +1 -0
  12. package/dist/web/assets/PersonalProfilePage-CSV9Mtgz.js +1 -0
  13. package/dist/web/assets/PersonalProfilePage-CVJ3TcRi.css +1 -0
  14. package/dist/web/assets/PersonalProjectsPage-A50EaseQ.js +1 -0
  15. package/dist/web/assets/PublicProjectsPage-BAdO_bae.js +1 -0
  16. package/dist/web/assets/ReviewPage-Dztk2jDG.js +1 -0
  17. package/dist/web/assets/console-tbvTUi6p.js +1 -0
  18. package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
  19. package/dist/web/assets/identity-B3s5CXhv.js +1 -0
  20. package/dist/web/assets/index-Devf7glZ.css +1 -0
  21. package/dist/web/assets/index-DwUDhQKc.js +6 -0
  22. package/dist/web/assets/model-DVT8sjy9.js +1 -0
  23. package/dist/web/assets/paths-B790iniO.js +1 -0
  24. package/dist/web/assets/runtime-dom.esm-bundler-DttsK21F.js +1 -0
  25. package/dist/web/assets/vue-router-BYTAoWT3.js +1 -0
  26. package/dist/web/index.html +22 -0
  27. package/graph-provider/Dockerfile +16 -0
  28. package/graph-provider/fuli_graph/__init__.py +5 -0
  29. package/graph-provider/fuli_graph/app.py +547 -0
  30. package/graph-provider/fuli_graph/auth.py +17 -0
  31. package/graph-provider/fuli_graph/collaboration_context.py +290 -0
  32. package/graph-provider/fuli_graph/config.py +34 -0
  33. package/graph-provider/fuli_graph/graph_models.py +123 -0
  34. package/graph-provider/fuli_graph/graph_projection.py +405 -0
  35. package/graph-provider/fuli_graph/graph_query.py +561 -0
  36. package/graph-provider/fuli_graph/knowledge_audit.py +765 -0
  37. package/graph-provider/fuli_graph/knowledge_batch_confirmation.py +246 -0
  38. package/graph-provider/fuli_graph/knowledge_management.py +816 -0
  39. package/graph-provider/fuli_graph/knowledge_records.py +65 -0
  40. package/graph-provider/fuli_graph/knowledge_search.py +723 -0
  41. package/graph-provider/fuli_graph/knowledge_usage_models.py +52 -0
  42. package/graph-provider/fuli_graph/model_validation.py +58 -0
  43. package/graph-provider/fuli_graph/models.py +1179 -0
  44. package/graph-provider/fuli_graph/personal_project_access.py +29 -0
  45. package/graph-provider/fuli_graph/preference_conflicts.py +420 -0
  46. package/graph-provider/fuli_graph/project_action_models.py +142 -0
  47. package/graph-provider/fuli_graph/project_knowledge.py +707 -0
  48. package/graph-provider/fuli_graph/project_management.py +251 -0
  49. package/graph-provider/fuli_graph/provider_values.py +40 -0
  50. package/graph-provider/fuli_graph/runtime.py +350 -0
  51. package/graph-provider/fuli_graph/search_projection.py +156 -0
  52. package/graph-provider/fuli_graph/store.py +24 -0
  53. package/graph-provider/fuli_graph/store_identity.py +237 -0
  54. package/graph-provider/fuli_graph/store_knowledge.py +447 -0
  55. package/graph-provider/fuli_graph/store_projects.py +242 -0
  56. package/graph-provider/fuli_graph/store_publication.py +370 -0
  57. package/graph-provider/fuli_graph/store_records.py +134 -0
  58. package/graph-provider/pyproject.toml +35 -0
  59. package/npm-shrinkwrap.json +6045 -0
  60. package/package.json +99 -0
  61. package/skills/capturing-session-knowledge/SKILL.md +226 -0
  62. package/skills/capturing-session-knowledge/agents/openai.yaml +13 -0
  63. package/skills/grilling-project/SKILL.md +129 -0
  64. package/skills/grilling-project/agents/openai.yaml +4 -0
  65. package/skills/grilling-project/references/project-profile.md +105 -0
  66. package/src/agent/candidate-read-service.js +53 -0
  67. package/src/agent/context-pack-service.js +83 -0
  68. package/src/agent/public-read-policy.js +39 -0
  69. package/src/agent/public-read-service.js +69 -0
  70. package/src/agent/read-projection.js +107 -0
  71. package/src/agent/search-service.js +61 -0
  72. package/src/agent/space-boundary.js +33 -0
  73. package/src/agent-tools/graph-definitions.js +479 -0
  74. package/src/agent-tools/graph-handlers.js +96 -0
  75. package/src/agent-tools/schema.js +37 -0
  76. package/src/agent-tools.js +16 -0
  77. package/src/app/application-error.js +13 -0
  78. package/src/app/bootstrap.js +8 -0
  79. package/src/app/create-application.js +143 -0
  80. package/src/app/state-service.js +38 -0
  81. package/src/candidates.js +78 -0
  82. package/src/classifier.js +63 -0
  83. package/src/cli/command-arguments.js +14 -0
  84. package/src/cli/command-registry.js +78 -0
  85. package/src/cli/commands/candidates.js +17 -0
  86. package/src/cli/commands/ingestion.js +32 -0
  87. package/src/cli/commands/reads.js +50 -0
  88. package/src/cli/commands/spaces.js +20 -0
  89. package/src/cli/invocation.js +47 -0
  90. package/src/cli/local-runtime-command.js +94 -0
  91. package/src/cli/local-runtime-options.js +64 -0
  92. package/src/cli/migrate-command.js +71 -0
  93. package/src/cli/migration-destination.js +117 -0
  94. package/src/cli/setup-agent-selection.js +195 -0
  95. package/src/cli/setup-command.js +85 -0
  96. package/src/cli/uninstall-command.js +67 -0
  97. package/src/cli.js +90 -0
  98. package/src/context-pack.js +206 -0
  99. package/src/defaults.js +1 -0
  100. package/src/extractor.js +77 -0
  101. package/src/fact-history.js +39 -0
  102. package/src/facts/fact-service.js +89 -0
  103. package/src/graphiti/agent-access-policy.js +88 -0
  104. package/src/graphiti/capture-policy.js +84 -0
  105. package/src/graphiti/federated-application.js +1292 -0
  106. package/src/graphiti/personal-context.js +29 -0
  107. package/src/graphiti/project-path-context.js +159 -0
  108. package/src/graphiti/provider-client.js +288 -0
  109. package/src/graphiti/runtime-config.js +85 -0
  110. package/src/graphiti/setup.js +43 -0
  111. package/src/graphiti/source-marker.js +142 -0
  112. package/src/http/api-router.js +133 -0
  113. package/src/http/bounded-json-array.js +19 -0
  114. package/src/http/error-mapping.js +36 -0
  115. package/src/http/graph-api-router.js +257 -0
  116. package/src/http/lens-route.js +50 -0
  117. package/src/http/request-policy.js +41 -0
  118. package/src/http/response.js +29 -0
  119. package/src/http/static-handler.js +55 -0
  120. package/src/ingestion.js +161 -0
  121. package/src/lens/lens-correction-service.js +81 -0
  122. package/src/lens/lens-fact-writer.js +85 -0
  123. package/src/lens/lens-input.js +62 -0
  124. package/src/lens/lens-query-projection.js +87 -0
  125. package/src/lens/lens-query-ranking.js +62 -0
  126. package/src/lens/lens-query.js +143 -0
  127. package/src/lens/lens-resource-projection.js +93 -0
  128. package/src/lens/lens-resource-selection.js +45 -0
  129. package/src/lens/lens-resource-service.js +103 -0
  130. package/src/lens/lens-search-query.js +122 -0
  131. package/src/lens/lens-service.js +183 -0
  132. package/src/local-runtime/lifecycle.js +254 -0
  133. package/src/mcp/create-mcp-server.js +85 -0
  134. package/src/mcp/instructions.js +10 -0
  135. package/src/mcp/project-action-preview-tokens.js +72 -0
  136. package/src/mcp/runtime.js +71 -0
  137. package/src/mcp/tool-annotations.js +63 -0
  138. package/src/mcp/tool-result.js +167 -0
  139. package/src/mcp/tool-schema.js +60 -0
  140. package/src/mcp-server.js +76 -0
  141. package/src/models.js +44 -0
  142. package/src/observer.js +83 -0
  143. package/src/package-metadata.js +6 -0
  144. package/src/project-rules.js +33 -0
  145. package/src/publication/canonical-json.js +39 -0
  146. package/src/publication/outbox-service.js +46 -0
  147. package/src/publication/publication-envelope-schema.js +75 -0
  148. package/src/publication/publication-envelope.js +37 -0
  149. package/src/publication/publication-policy.js +82 -0
  150. package/src/publication/publication-service.js +48 -0
  151. package/src/router.js +58 -0
  152. package/src/runtime-options.js +139 -0
  153. package/src/security/episode-visibility.js +14 -0
  154. package/src/security/fact-visibility.js +15 -0
  155. package/src/security/sensitive-content.js +18 -0
  156. package/src/security/source-metadata-policy.js +8 -0
  157. package/src/server/application-lifecycle.js +34 -0
  158. package/src/server/listen.js +24 -0
  159. package/src/server.js +135 -0
  160. package/src/setup/agent-installation-status.js +97 -0
  161. package/src/setup/agents.js +123 -0
  162. package/src/setup/codex-bootstrap.js +118 -0
  163. package/src/setup/codex-config.js +122 -0
  164. package/src/setup/config-backup.js +22 -0
  165. package/src/setup/container-runtime.js +388 -0
  166. package/src/setup/cursor-config.js +61 -0
  167. package/src/setup/graph-runtime.js +360 -0
  168. package/src/setup/node-runtime.js +24 -0
  169. package/src/setup/options.js +91 -0
  170. package/src/setup/paths.js +47 -0
  171. package/src/setup/session-skill.js +91 -0
  172. package/src/setup/setup.js +85 -0
  173. package/src/setup/uninstall.js +90 -0
  174. package/src/storage/episode-evidence-preview.js +100 -0
  175. package/src/storage/fact-search-order.js +18 -0
  176. package/src/storage/file/episode-evidence.js +37 -0
  177. package/src/storage/file/episode-index.js +59 -0
  178. package/src/storage/file/fact-search.js +60 -0
  179. package/src/storage/file-store.js +437 -0
  180. package/src/storage/import-json.js +70 -0
  181. package/src/storage/json-file.js +41 -0
  182. package/src/storage/legacy-record-validation.js +152 -0
  183. package/src/storage/legacy-snapshot-validation.js +32 -0
  184. package/src/storage/migrate.js +128 -0
  185. package/src/storage/migrations/001-initial.sql +83 -0
  186. package/src/storage/migrations/002-storage-integrity.sql +113 -0
  187. package/src/storage/record-validation.js +46 -0
  188. package/src/storage/snapshot-defaults.js +54 -0
  189. package/src/storage/sqlite/candidates-repository.js +84 -0
  190. package/src/storage/sqlite/episode-evidence-repository.js +154 -0
  191. package/src/storage/sqlite/episode-privacy-sql.js +33 -0
  192. package/src/storage/sqlite/episodes-repository.js +52 -0
  193. package/src/storage/sqlite/fact-search-repository.js +162 -0
  194. package/src/storage/sqlite/facts-repository.js +146 -0
  195. package/src/storage/sqlite/imports-repository.js +39 -0
  196. package/src/storage/sqlite/mapper.js +84 -0
  197. package/src/storage/sqlite/open-database.js +15 -0
  198. package/src/storage/sqlite/outbox-repository.js +103 -0
  199. package/src/storage/sqlite/snapshot-repository.js +69 -0
  200. package/src/storage/sqlite/spaces-repository.js +52 -0
  201. package/src/storage/sqlite/subscriptions-repository.js +54 -0
  202. package/src/storage/sqlite-store.js +159 -0
  203. package/src/storage/stable-json.js +24 -0
  204. package/src/storage/store-port.js +20 -0
  205. package/src/store.js +2 -0
  206. package/src/workspace-protocol/array-validation.js +19 -0
  207. package/src/workspace-protocol/base64url-contract.js +27 -0
  208. package/src/workspace-protocol/constants.js +37 -0
  209. package/src/workspace-protocol/error-contract.js +24 -0
  210. package/src/workspace-protocol/fact-contract.js +110 -0
  211. package/src/workspace-protocol/governance-contract.js +47 -0
  212. package/src/workspace-protocol/index.js +53 -0
  213. package/src/workspace-protocol/json-budget.js +19 -0
  214. package/src/workspace-protocol/manifest-contract.js +186 -0
  215. package/src/workspace-protocol/publication-contract.js +212 -0
  216. package/src/workspace-protocol/query-contract.js +149 -0
  217. package/src/workspace-protocol/scalar-contract.js +192 -0
  218. package/src/workspace-protocol/sync-contract.js +184 -0
  219. package/src/workspace-protocol/text-contract.js +39 -0
  220. package/src/workspace-protocol/validation.js +66 -0
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "fuli-context",
3
+ "version": "0.2.0",
4
+ "description": "Local-first context graph for AI agents.",
5
+ "type": "module",
6
+ "files": [
7
+ "npm-shrinkwrap.json",
8
+ "src/",
9
+ "dist/web/",
10
+ "graph-provider/Dockerfile",
11
+ "graph-provider/pyproject.toml",
12
+ "graph-provider/fuli_graph/*.py",
13
+ "graph-provider/fuli_graph/**/*.py",
14
+ "skills/",
15
+ "compose.graphiti.yml"
16
+ ],
17
+ "bin": {
18
+ "fl": "./src/cli.js",
19
+ "fuli": "./src/cli.js"
20
+ },
21
+ "keywords": [
22
+ "ai-agent",
23
+ "mcp",
24
+ "context",
25
+ "knowledge-graph",
26
+ "local-first",
27
+ "codex",
28
+ "claude-code"
29
+ ],
30
+ "scripts": {
31
+ "mcp": "node src/mcp-server.js",
32
+ "dev": "run-p dev:server dev:web",
33
+ "dev:server": "node src/server.js",
34
+ "dev:web": "vite",
35
+ "build": "run-s typecheck:web build:web",
36
+ "build:web": "vite build",
37
+ "typecheck:web": "vue-tsc --noEmit -p tsconfig.app.json",
38
+ "test:node": "node --test",
39
+ "test:web": "vitest run --config vitest.config.ts",
40
+ "test:package": "node scripts/package-smoke.js",
41
+ "test:knowledge:live": "node acceptance/knowledge-live.js",
42
+ "start": "node src/server.js",
43
+ "graph:setup": "node src/graphiti/setup.js",
44
+ "graph:up": "docker compose -f compose.graphiti.yml up -d --build",
45
+ "graph:down": "docker compose -f compose.graphiti.yml down",
46
+ "test:structure": "node --test test/source-structure.test.js",
47
+ "pretest": "npm run build:web",
48
+ "test": "run-s typecheck:web test:node test:web",
49
+ "prepack": "npm run build",
50
+ "prepublishOnly": "npm test"
51
+ },
52
+ "engines": {
53
+ "node": ">=24.12"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/JevonsCode/fuli.git"
58
+ },
59
+ "homepage": "https://github.com/JevonsCode/fuli#readme",
60
+ "bugs": {
61
+ "url": "https://github.com/JevonsCode/fuli/issues"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "license": "Apache-2.0",
67
+ "dependencies": {
68
+ "@hono/node-server": "2.0.12",
69
+ "@modelcontextprotocol/sdk": "^1.29.0",
70
+ "better-sqlite3": "^12.11.1",
71
+ "zod": "^4.4.3"
72
+ },
73
+ "devDependencies": {
74
+ "@types/d3": "^7.4.3",
75
+ "@types/node": "^24.13.3",
76
+ "@vitejs/plugin-vue": "^6.0.8",
77
+ "@vue/test-utils": "^2.4.11",
78
+ "brace-expansion": "5.0.8",
79
+ "d3": "^7.9.0",
80
+ "gsap": "^3.15.0",
81
+ "jsdom": "^29.1.1",
82
+ "linkedom": "^0.18.12",
83
+ "npm-run-all2": "^9.0.2",
84
+ "pinia": "^4.0.2",
85
+ "typescript": "~6.0.0",
86
+ "vite": "^8.1.5",
87
+ "vitest": "^4.1.10",
88
+ "vue": "^3.5.40",
89
+ "vue-router": "^5.2.0",
90
+ "vue-tsc": "^3.3.8"
91
+ },
92
+ "overrides": {
93
+ "@modelcontextprotocol/sdk": {
94
+ "@hono/node-server": "2.0.12"
95
+ },
96
+ "brace-expansion": "$brace-expansion",
97
+ "fast-uri": "3.1.4"
98
+ }
99
+ }
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: capturing-session-knowledge
3
+ description: Use when Fuli tools are available and a task may depend on remembered personal preferences or durable project facts such as URLs, routes, requirements, architecture, prior decisions, runbooks, or rationale, or when ordinary work produces reusable knowledge worth retaining.
4
+ ---
5
+
6
+ # Capturing Session Knowledge
7
+
8
+ Accumulate reusable knowledge without interrupting the user's normal work. Keep an internal session buffer and flush focused batches at a natural task boundary or before the session ends.
9
+
10
+ ## Load Collaboration Preferences
11
+
12
+ At the start of every user task, before any other tool or answer, call
13
+ `get_collaboration_preferences`. Pass `projectPath` as the current working directory. Fuli uses
14
+ that path only for this local MCP call, never stores or returns it, and resolves the exact local
15
+ personal project itself. Do not infer or guess `personalProjectId` in the Agent.
16
+
17
+ Apply only `effective_preferences`. Personal-global preferences apply in every user task;
18
+ project-scoped preferences layer on only for the exact selected project. Do not apply items
19
+ listed as conflicts, and do not borrow preferences from a related, similarly named, or guessed
20
+ project. Human or authoritative-source confirmation outranks explicitly marked
21
+ `agent_confirmed` preferences. Pending preferences remain search-only; invalid and
22
+ unrelated-project preferences are intentionally excluded. Automatic preference injection is
23
+ not usage evidence.
24
+ When `get_collaboration_preferences` returns a `deferred_conflict`, leave it untouched unless
25
+ the current task would use either side. Before using a relevant deferred conflict, compare both
26
+ sides and call `resolve_deferred_preference_conflict`; apply only the successfully resolved
27
+ result. The resolution record must remain marked as previously conflicted and AI-resolved.
28
+ Before any write tool call, enforce every applicable preference in the actual payload.
29
+ Mentioning a preference only in the final answer is not compliance.
30
+
31
+ ## Retrieve Context
32
+
33
+ Call `search_knowledge_graph` when prior durable context can materially improve the task.
34
+ Before saying that a stable fact is unknown or asking the user to provide it again, search
35
+ Fuli if it may have been learned earlier. Strong triggers include URLs, deployment routes,
36
+ requirements, terminology, architecture, prior decisions, runbooks, rationale, and remembered
37
+ personal preferences. Do not search for a fully self-contained task or use Fuli as proof of live
38
+ external state.
39
+
40
+ Pending knowledge is eligible for on-demand retrieval and must remain visibly marked.
41
+ `agent_confirmed` knowledge is usable but ranks below user or authoritative-source
42
+ confirmation.
43
+
44
+ Treat an obvious content-location request specially: examples include asking for a named page,
45
+ URL, route, deployment, document, file, or where a durable artifact is located.
46
+
47
+ 1. Run one bounded search that preserves distinctive names, identifiers, and quoted phrases from
48
+ the user's wording. Do not dilute them with generic expansion. An unrelated result is no
49
+ evidence even if the tool labels it matched.
50
+ 2. If there is no supporting result, ask whether to widen this one read-only lookup to all
51
+ registered local personal projects and, if still unresolved, the current repository or
52
+ workspace files. Explain that it applies only to this lookup, excludes public projects and
53
+ paths outside the current workspace, then stop and wait for the user's answer.
54
+ 3. Only after explicit confirmation, call `search_knowledge_graph` again with
55
+ `personalProjectScope: all_local_confirmed`. Never infer consent from the lookup intent itself.
56
+ 4. This expanded scope does not expand any public project or subscription and must not become a
57
+ persistent default. If it still has no supporting result, continue with a local file fallback:
58
+ - When the current directory is inside one repository, search only that repository.
59
+ - When it is an intentional multi-repository workspace root, search only that workspace.
60
+ - When it is the user home, filesystem root, or otherwise too broad or ambiguous, ask for an
61
+ exact safe repository/workspace root and stop. Never recursively scan a home or system root.
62
+ - Within the safe root, use read-only `Grep`/`Glob`/`Read` or `rg`. Preserve the exact quoted
63
+ name first, respect ignore rules, and inspect only relevant matches and routing/deployment
64
+ context. Do not inspect credential stores, browser data, secrets, or paths outside the root.
65
+ - A route string alone is not a live URL. Require deployment-domain or equivalent evidence.
66
+ If local files still provide no supporting evidence, ask for a project, document, or source
67
+ clue.
68
+
69
+ Personal retrieval always includes the bounded personal-global profile. For a local personal
70
+ project, pass its exact `personalProjectId`; if the user explicitly names another personal
71
+ project, resolve it with `list_personal_projects` and add only that exact ID through
72
+ `contextPersonalProjectIds`. Without an active local project, search only the personal-global
73
+ profile. For public context, pass only the active or explicitly named subscribed public project
74
+ IDs; never search every personal project, every subscription, or the whole graph by default.
75
+ Use the current repository, the user's wording, and `list_knowledge_spaces` to resolve scope.
76
+ Ask if the active project remains ambiguous.
77
+
78
+ The active project may also retrieve only knowledge explicitly marked inheritable from projects
79
+ reached through outgoing `PART_OF` or `USES_KNOWLEDGE_FROM` relations. Never inherit
80
+ project-scoped personal preferences, never traverse `RELATED_TO`, stop after two hops, and retain
81
+ the returned scope path. Exact active-project knowledge with the same stable key overrides an
82
+ inherited item.
83
+
84
+ After a retrieved personal item materially affects the final answer or a completed action, call
85
+ `record_knowledge_usage` once for that task and item with `cited` or `applied`. Do not record
86
+ retrieval, inspection, automatic preference injection, or unused context. Usage evidence can
87
+ promote only to `agent_confirmed`; it never substitutes for human confirmation or makes an item
88
+ eligible for public publication. Use the current user task's caller-stable identifier as
89
+ `taskId` and reuse it on retries; never generate another ID to recount the same task.
90
+
91
+ The current `agent-usage-v1` policy requires at least five idempotent material-use events across
92
+ at least three distinct tasks in the current content generation, with no open knowledge or
93
+ preference conflict. It maintains utility and confidence as separate scores and caps
94
+ Agent-confirmed confidence below human/source confirmation. Agents report qualifying use; they
95
+ do not calculate, override, or claim the promotion themselves.
96
+
97
+ For “why was this code written?” questions, use stored evidence relationships and a separately configured Git MCP together. Never invent a commit, PRD link, or missing history. For “what errors happened today?” questions, obtain current data from a monitoring/log MCP; use Fuli only for runbooks, architecture, prior causes, and other durable context.
98
+
99
+ Every `search_knowledge_graph` response provides two terminal-safe Markdown choices:
100
+ `sourceMarker` for returned items that support the answer, and `noMatchSourceMarker`
101
+ for a search with no supporting result. A tool-labelled match that is irrelevant to
102
+ the answer still requires `noMatchSourceMarker`.
103
+
104
+ For the chosen marker, the final answer must begin with its `leadMarkdown` unchanged,
105
+ before any heading or prose, and append its `markdown` unchanged after the answer. If
106
+ any search supports the answer, choose `sourceMarker` from one supporting search. If
107
+ none do, choose `noMatchSourceMarker`. Never show either marker when no search was
108
+ called. Never fabricate, rewrite, omit, or wrap markers in HTML. A capture or write
109
+ result is not a read citation.
110
+
111
+ ## Decide What Persists
112
+
113
+ Capture confirmed, stable information:
114
+
115
+ - Personal: the user's enduring preferences, boundaries, habits, and working methods. Project-specific personal rules must explicitly link to that project instead of becoming global defaults.
116
+ - Project: PRD facts, requirements, terminology, decisions, constraints, architecture, routes, APIs, metrics, and document-derived knowledge.
117
+
118
+ Do not capture credentials, tokens, cookies, private keys, raw transcripts, temporary logs, command output, speculative conclusions, or disposable implementation details. Treat a correction as a replacement, not an additional conflicting fact.
119
+
120
+ ## Classify Knowledge State
121
+
122
+ Every entity and relationship needs an `originQuadrant`, `confirmationBasis`, and
123
+ `confirmationStatus`. These fields answer three separate questions:
124
+
125
+ 1. `originQuadrant` records how the item was discovered. It is not a truth score and does
126
+ not change merely because the item is later confirmed.
127
+ 2. `confirmationBasis` explains why the item exists, why it belongs to that quadrant,
128
+ who proposed it, and—when confirmed—who confirmed it and when.
129
+ 3. `confirmationStatus` is `pending`, `agent_confirmed`, or `confirmed`.
130
+
131
+ Keep the canonical quadrant names:
132
+
133
+ - `known_known`: knowledge or a conclusion that was explicitly expressed when captured.
134
+ - `known_unknown`: an unresolved question or tradeoff that was explicitly recognized.
135
+ - `unknown_known`: tacit knowledge inferred from behaviour, examples, prototypes, or
136
+ reactions.
137
+ - `unknown_unknown`: a potential blind spot surfaced during open exploration. A truly
138
+ unknown item cannot be stored; this label describes how the recorded candidate arose.
139
+
140
+ Every `confirmationBasis` must contain:
141
+
142
+ - `existenceReason`: why this item was created;
143
+ - `quadrantReason`: why it was assigned to this quadrant;
144
+ - `proposedBy`: `{ kind, label }`, where kind is `user`, `agent`,
145
+ `authoritative_source`, or `import`;
146
+ - `confirmedBy` and `confirmedAt` together when confirmed.
147
+
148
+ An Agent may propose and explain knowledge. A user or authoritative source creates
149
+ `confirmed`; a deterministic Fuli usage policy may create only `agent_confirmed`, with an Agent
150
+ confirmer, timestamp, and policy version. Agent confirmation is lower-authority, never
151
+ public-eligible, and must not be produced by retrieval alone. Confirmation covers the content
152
+ and its classification. If either changes, return the item to `pending` and start a new usage
153
+ generation unless the same revision explicitly records a new valid human/source confirmer and
154
+ confirmation time. Legacy items without that audit record are `pending`, even if an old
155
+ `epistemicStatus` said `confirmed`.
156
+
157
+ `currentQuadrant` and `epistemicStatus` are legacy compatibility fields. Do not use them
158
+ for new product logic and do not treat them as confirmation evidence.
159
+
160
+ Agent retrieval includes pending items on demand and returns their status so the caller can
161
+ calibrate claims. Only user or authoritative-source `confirmed` project knowledge may enter
162
+ public review, regardless of how it was originally discovered; normal personal preview and
163
+ Maintainer review gates still apply.
164
+
165
+ ## Grow The Personal Profile Separately
166
+
167
+ Durable facts about the person's collaboration style use `profileAspect`. They default to
168
+ the personal-global graph without `personalProjectId`:
169
+
170
+ - `taste`: aesthetic, writing, product, architecture, or engineering outcomes the user
171
+ likes or rejects.
172
+ - `personality`: stable self-described collaboration or working traits. Agent-inferred
173
+ personality stays `pending` and must never be silently promoted to confirmed.
174
+ - `judgment_preference`: repeated decision criteria, tradeoff priorities, risk posture,
175
+ and conditions that change how the user chooses.
176
+
177
+ When the user explicitly limits one preference to a project, keep `profileAspect` and capture
178
+ it with that exact `personalProjectId`; this makes the preference project-scoped without
179
+ turning it into public project knowledge. Use `set_personal_preference_scope` when the user
180
+ later changes the scope. Never put any personal-profile item into a public proposal.
181
+ For a preference that may have both global and project-specific forms, store a stable
182
+ `attributes.preferenceKey` on each form so the project value can explicitly override the same
183
+ global decision without hiding unrelated preferences.
184
+
185
+ ## Route by Ownership
186
+
187
+ - Route global personal knowledge to `targetKind: personal` without `personalProjectId`; it is written directly to the local personal graph.
188
+ - Route knowledge for a local personal project, including an explicitly project-scoped personal preference, to `targetKind: personal` with that project's exact `personalProjectId`. This is private local knowledge, not a public submission.
189
+ - Route knowledge to `targetKind: project` only when the target is an explicitly selected subscribed public project. It becomes a team-shared Provider Proposal and must remain pending until a Maintainer reviews it.
190
+ - Never treat a project as public merely because the current repository or conversation has a project name. Only an active subscription makes it eligible for public project routing.
191
+ - Never omit `personalProjectId` when the current repository or conversation has already resolved one local personal project; doing so would leak project-specific facts into the personal-global scope.
192
+ - Never add another personal project to `contextPersonalProjectIds` merely because it is related, similarly named, or referenced by the active project. Automatic borrowing is limited to item-level inheritable knowledge reached through `PART_OF` or `USES_KNOWLEDGE_FROM`; all other cross-project borrowing requires an explicit user request or selection and applies only to the current search context.
193
+ - Never route project facts through the personal graph to bypass review.
194
+ - Never auto-approve a project Proposal.
195
+ - If ownership is genuinely ambiguous and changes who can see the knowledge, ask one concise question instead of guessing.
196
+
197
+ ## Resolve Or Create The Local Project
198
+
199
+ Before the first project-scoped capture in a repository:
200
+
201
+ 1. Call `list_knowledge_spaces`, then `list_personal_projects` for the active personal space.
202
+ 2. Resolve the repository root from the current working directory and repo-local manifests. Use a stable, human-readable project ID derived from the repository or manifest name. Never store an absolute path, local username, hostname, credential, or private remote URL as the project ID or public profile evidence.
203
+ 3. Match an existing personal project by exact project ID, publication mapping, or confirmed repository identity. Do not merge projects from similar names.
204
+ 4. When one previously unseen repository has an unambiguous identity, immediately create a minimal private personal project with `upsert_personal_project`. Use lifecycle `active`, a private repository source with no URI, and an evidence-coverage summary containing only facts visible in the current repository. Do not generate a generic list of information the project supposedly lacks.
205
+ 5. Ask one project-identity question only when the working directory contains multiple plausible projects or the repository identity conflicts with an existing project.
206
+
207
+ Creating a personal project is local classification, not public publication. Never create or subscribe to a public project automatically.
208
+
209
+ ## Structure and Flush
210
+
211
+ Use `capture_session_knowledge` with a small, coherent batch:
212
+
213
+ 1. List spaces when the target IDs are not already known.
214
+ 2. Summarize the durable facts; do not submit the entire source document or conversation.
215
+ 3. Create stable entity keys, typed entities, and explicit uppercase relationships. When relevant, model `GitCommit`, `CodeSymbol`, `PRDSection`, `Runbook`, and `Incident` entities and connect them with relationships such as `IMPLEMENTED_IN`, `DEFINED_BY`, `MOTIVATED_BY`, `APPLIES_TO`, and `INVESTIGATED_WITH`.
216
+ 4. Include source kind, source application, a non-sensitive source description, reference time, session ID, and a retry-safe idempotency key. When available, include a stable source turn ID and only the smallest relevant excerpt needed to understand the evidence; never include a full transcript.
217
+ 5. Use `supersedes` when replacing a known relationship and set confidence below `1` only when the source itself expresses uncertainty.
218
+ 6. Flush silently at the boundary. Continue the user's task without narrating routine capture.
219
+
220
+ If `capture_session_knowledge` or automatic project creation returns `capture_disabled`, the
221
+ user has disabled automatic capture. Do not retry, do not create a fallback record elsewhere,
222
+ and do not describe the skipped batch as stored. Existing knowledge may still be queried.
223
+
224
+ Before sending the final response, perform one checkpoint: either flush the durable batch or determine that this turn produced no reusable knowledge. Do not finish a reusable project decision with an unflushed batch.
225
+
226
+ Only notify the user when capture fails, conflicts with existing knowledge, or requires an ownership decision. If project knowledge was proposed successfully, do not interrupt merely to announce the pending review item.
@@ -0,0 +1,13 @@
1
+ interface:
2
+ display_name: "Capturing Session Knowledge"
3
+ short_description: "Recall and retain durable personal and project context"
4
+ default_prompt: "Use $capturing-session-knowledge to load effective collaboration preferences, retrieve relevant durable context, and retain reusable knowledge in Fuli."
5
+
6
+ dependencies:
7
+ tools:
8
+ - type: "mcp"
9
+ value: "fuli"
10
+ description: "Local Fuli Graphiti knowledge tools"
11
+
12
+ policy:
13
+ allow_implicit_invocation: true
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: grilling-project
3
+ description: Use when creating, clarifying, updating, assessing, or publishing a Fuli project profile, especially when the user has only a partial project description or asks to add PRDs, technical documents, frontend/backend repositories, runbooks, monitoring, scope, or public-project metadata. Interview one question at a time, discover repository facts first, record confirmed personal project information progressively, and never publish before a final public-boundary preview is confirmed.
4
+ ---
5
+
6
+ # Grilling Project
7
+
8
+ Turn incomplete project knowledge into an evidence-backed Fuli personal project profile, then optionally publish it. Keep the interview light: discover what can be discovered, ask one useful question, recommend an answer, and wait.
9
+
10
+ Read [project-profile.md](references/project-profile.md) before assessing evidence coverage or constructing a project profile.
11
+
12
+ ## Non-negotiable behavior
13
+
14
+ - During the interview, ask exactly one question in each question-bearing message. Pure status or failure notifications do not need a synthetic question.
15
+ - Before asking, use read-only repository inspection to discover relevant facts that are already available.
16
+ - State the current inference separately from confirmed facts.
17
+ - Include a recommended answer and explain its consequence briefly.
18
+ - Do not publish a public project until the user confirms a final publication preview.
19
+ - Evidence coverage is display-only. Never block publication because the score is low.
20
+ - Record confirmed information in the personal graph as the interview progresses. Personal recording is not public publication.
21
+ - Do not silently turn a related project into a subscription. Subscription is always explicit.
22
+
23
+ ## Start with Fuli state
24
+
25
+ 1. Call `list_knowledge_spaces` to learn the active personal space, public Provider state, subscriptions, and public projects.
26
+ 2. Call `list_personal_projects` for the active personal space.
27
+ 3. Match by stable project ID or an existing publication mapping first. Use repository evidence second. Never merge projects from name similarity alone; ask one identity question when the match is ambiguous.
28
+ 4. If a public project already corresponds to it, treat publication as a profile sync, not a second project.
29
+
30
+ Use a stable, human-readable `projectId` derived from the repository/project name. Do not derive it from a local absolute path, username, hostname, or confidential identifier.
31
+
32
+ ## Discover before asking
33
+
34
+ Inspect only the current project and directly relevant files. Typical evidence includes:
35
+
36
+ - README and project documentation indexes
37
+ - package or build manifests
38
+ - architecture and deployment documents
39
+ - repository-local Git remotes
40
+ - frontend/backend directory layout
41
+ - run, test, deployment, rollback, monitoring, and incident instructions
42
+
43
+ Do not read global Git configuration, credential helpers, SSH configuration, tokens, unrelated repositories, browser data, or secret stores. Treat internal URLs and repository remotes as private evidence until the user explicitly approves public inclusion.
44
+
45
+ Label every proposed fact as one of:
46
+
47
+ - **confirmed** — directly stated by the user or supported by inspected evidence
48
+ - **inferred** — plausible but not yet confirmed
49
+
50
+ Summarize only information and evidence that currently exist. Do not present a generated
51
+ list of “missing items”; absence from a generic checklist is not evidence that the project
52
+ actually needs that item.
53
+
54
+ Do not ask the user for a fact that can be verified safely from the current repository.
55
+
56
+ ## Interview loop
57
+
58
+ Choose the highest-impact clarification that follows from the user's goal or current
59
+ evidence. Do not manufacture questions solely to fill a generic checklist. In each turn:
60
+
61
+ 1. Summarize newly confirmed facts in one or two sentences.
62
+ 2. State any relevant inference and its evidence.
63
+ 3. Ask one question only.
64
+ 4. Put the recommended answer first and explain the tradeoff.
65
+ 5. Wait for the answer.
66
+
67
+ Prefer project identity, purpose, scope, and privacy boundary before lower-impact metadata. Skip resolved categories. If the user rejects a recommendation, record their choice without repeatedly arguing.
68
+
69
+ After a meaningful confirmed update, call `upsert_personal_project` with the complete current profile, not a partial patch. Preserve earlier confirmed fields and sources. Routine successful updates stay quiet.
70
+
71
+ ## Evidence coverage assessment
72
+
73
+ Recompute the assessment when evidence changes. Follow the dimensions and scoring guidance in the reference.
74
+
75
+ The assessment must contain:
76
+
77
+ - an overall score and label
78
+ - confirmed facts
79
+ - clearly marked inferences
80
+ - dimension-level evidence already present
81
+ - `analyzedAt` set to the current time
82
+
83
+ Never inflate the score from a filename alone. A discovered link confirms that a source exists, not that its content is current or complete. Never present inference as confirmed.
84
+
85
+ ## Publication gate
86
+
87
+ When the profile is useful enough for the user to review—or the user asks to publish—show one final preview containing:
88
+
89
+ - project name, purpose, scope, and lifecycle
90
+ - public sources and links
91
+ - excluded private or restricted sources
92
+ - confirmed and inferred existing information
93
+ - evidence coverage score with the sentence “资料覆盖仅用于展示,不影响发布”
94
+ - the selected public Provider
95
+ - the consequences: publisher becomes Owner and Maintainer, and the personal space is automatically subscribed
96
+
97
+ Ask one final question: whether to publish this exact preview. Recommend publishing when the public boundary is clear; sparse evidence does not block publication.
98
+
99
+ If more than one public Provider is ready and no existing project mapping determines the target, ask one Provider-selection question before the final preview. Do not select the first Provider implicitly.
100
+
101
+ Confirmation approves only the public sources and links individually listed in that preview. Unlisted sources remain private or restricted.
102
+
103
+ Only after explicit confirmation, call `publish_personal_project` with `personalSpaceId`, `localProjectId`, and `providerUrl` from the preview.
104
+
105
+ If no public Provider is connected:
106
+
107
+ - continue building the personal project profile normally
108
+ - do not offer a fake or queued publication
109
+ - explain once, when relevant, that public publication is unavailable until a Provider is connected
110
+ - do not automatically replay publication later
111
+
112
+ ## Project relationships
113
+
114
+ Use `create_project_relation` only after both public projects are identified and the user confirms the relationship type.
115
+
116
+ - `PART_OF` means a real hierarchy and requires confirmation by a Maintainer of the parent project.
117
+ - `DEPENDS_ON` means a runtime, delivery, or development dependency.
118
+ - `PROVIDES_TO` means one project supplies a capability to another.
119
+ - `SHARES_CAPABILITY_WITH` means reusable capability overlap without hierarchy.
120
+ - `SUCCESSOR_OF` means replacement or evolution.
121
+ - `RELATED_TO` is the fallback when no stronger semantics are confirmed.
122
+
123
+ Do not use `PART_OF` merely because two projects are in the same business domain. Do not subscribe to the related project unless the user separately asks.
124
+
125
+ ## Safety
126
+
127
+ Never record or publish credentials, tokens, cookies, private keys, personal/personnel information, or unrelated machine details. Keep confidential material out of names, summaries, source titles, URIs, assessment evidence, and publication previews.
128
+
129
+ Sources marked `private` or `restricted` may remain in the personal profile but cannot be sent to the public Provider. If the public profile would reveal company-confidential information, stop and ask one boundary question before proceeding.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Grilling Project"
3
+ short_description: "一次一问地澄清项目资料、已有证据覆盖与公共发布边界"
4
+ default_prompt: "Use $grilling-project to clarify this project one question at a time before recording or publishing it."
@@ -0,0 +1,105 @@
1
+ # Fuli project profile reference
2
+
3
+ Use this reference to construct the complete payload for `upsert_personal_project`.
4
+ Optional fields may be absent. Publication is never blocked by this guidance.
5
+
6
+ ## Profile fields
7
+
8
+ - `name`: confirmed user-facing project name
9
+ - `purpose`: problem solved, primary users, and intended outcome
10
+ - `scope`: included and excluded product or technical boundaries
11
+ - `technicalSummary`: architecture, important modules, runtimes, and constraints
12
+ - `lifecycle`: `planned`, `active`, `maintenance`, or `archived`
13
+ - `sources`: evidence records described below
14
+ - `boundaries`: durable development, ownership, privacy, and operational rules
15
+ - `assessment`: evidence-backed summary of information currently recorded
16
+
17
+ ## Source records
18
+
19
+ Every source needs a stable `key`, `kind`, and `title`. Add `uri` and `summary` only when supported by evidence.
20
+
21
+ Supported kinds:
22
+
23
+ - `prd`
24
+ - `product_document`
25
+ - `technical_document`
26
+ - `frontend_repository`
27
+ - `backend_repository`
28
+ - `repository`
29
+ - `design`
30
+ - `runbook`
31
+ - `monitoring`
32
+ - `issue_tracker`
33
+ - `other`
34
+
35
+ Set sensitivity to:
36
+
37
+ - `normal` only when the source is approved for public inclusion
38
+ - `private` for personal or non-public project evidence
39
+ - `restricted` for highly controlled evidence that must never reach a public Provider
40
+
41
+ Do not store credentials at any sensitivity.
42
+
43
+ ## Evidence coverage dimensions
44
+
45
+ Use these dimensions only to summarize evidence already present, not to declare what a
46
+ project is missing. Each dimension has a 0–100 coverage score. The overall score should
47
+ be a reasoned weighted average of supported evidence, not an unexamined count of links.
48
+
49
+ 1. `identity` — purpose, users, lifecycle, scope, and exclusions
50
+ 2. `product` — PRD or equivalent product evidence and current requirements
51
+ 3. `technical` — architecture, key modules, interfaces, and constraints
52
+ 4. `code` — confirmed frontend/backend repositories and ownership boundaries
53
+ 5. `operations` — run, deploy, rollback, monitoring, and incident evidence
54
+ 6. `governance` — privacy boundary, contribution rules, maintainership, and durable development rules
55
+
56
+ Suggested weighting:
57
+
58
+ - identity: 20%
59
+ - product: 20%
60
+ - technical: 20%
61
+ - code: 20%
62
+ - operations: 10%
63
+ - governance: 10%
64
+
65
+ Scoring evidence:
66
+
67
+ - 80–100: current, direct, and sufficiently detailed evidence
68
+ - 50–79: partial evidence with material gaps
69
+ - 20–49: mainly user statements or weak/inferred evidence
70
+ - 0–19: no usable evidence currently recorded or evidence is contradicted
71
+
72
+ Overall labels:
73
+
74
+ - `needs_clarification`: 0–39
75
+ - `partially_documented`: 40–74
76
+ - `well_documented`: 75–100
77
+
78
+ Each dimension contains:
79
+
80
+ - `key`
81
+ - `label`
82
+ - `score`
83
+ - `state`: `confirmed` or `inferred`
84
+ - `evidence`: short statements pointing to the evidence
85
+
86
+ The assessment contains `confirmed` and `inferred` summaries only. It does not contain a
87
+ generated `missing` list. A zero score means Fuli currently has no usable evidence for
88
+ that dimension; it does not claim the project must add a particular artifact.
89
+
90
+ ## Publication checklist
91
+
92
+ Before asking for final confirmation, verify the preview explicitly covers:
93
+
94
+ - project purpose and scope
95
+ - PRD/product documentation
96
+ - technical documentation
97
+ - frontend and backend repository evidence
98
+ - runbook or local run/deployment instructions
99
+ - monitoring and error-diagnosis instructions
100
+ - privacy and public-sharing boundary
101
+ - durable project development rules
102
+ - confirmed and inferred existing information
103
+ - Owner/automatic-subscription consequence
104
+
105
+ Sparse evidence never prevents publication.
@@ -0,0 +1,53 @@
1
+ import { SpaceKind } from '../models.js';
2
+ import { isSafeAgentText } from './public-read-policy.js';
3
+ import { requirePersonalSpace } from './space-boundary.js';
4
+
5
+ export class AgentCandidateReadService {
6
+ constructor(store) {
7
+ this.store = store;
8
+ }
9
+
10
+ list(personalSpaceId) {
11
+ requirePersonalSpace(this.store, personalSpaceId);
12
+ return this.store.pendingCandidates(personalSpaceId)
13
+ .map((candidate) => this.#project(candidate, personalSpaceId));
14
+ }
15
+
16
+ listForSpace(personalSpaceId, spaceId) {
17
+ return this.list(personalSpaceId)
18
+ .filter((candidate) => !candidate.targetSpaceId || candidate.targetSpaceId === spaceId);
19
+ }
20
+
21
+ #project(candidate, personalSpaceId) {
22
+ const resolvedTarget = candidate.targetSpaceId
23
+ ? this.store.getSpace(candidate.targetSpaceId)
24
+ : null;
25
+ const target = resolvedTarget?.kind === SpaceKind.PUBLIC ? resolvedTarget : null;
26
+ return {
27
+ id: candidate.id,
28
+ reason: isSafeAgentText(candidate.reason) ? candidate.reason : null,
29
+ status: candidate.status,
30
+ createdAt: candidate.createdAt,
31
+ targetSpaceId: target?.id ?? null,
32
+ targetSpaceName: target?.name ?? null,
33
+ source: this.#source(candidate.episodeId, personalSpaceId)
34
+ };
35
+ }
36
+
37
+ #source(episodeId, personalSpaceId) {
38
+ const episode = this.store.getEpisode(episodeId);
39
+ if (!episode || episode.spaceId !== personalSpaceId) return null;
40
+ if (![
41
+ episode.sourceKind,
42
+ episode.sourceUri,
43
+ episode.body,
44
+ JSON.stringify(episode.metadata)
45
+ ].every(isSafeAgentText)) return null;
46
+ return {
47
+ id: episode.id,
48
+ kind: episode.sourceKind,
49
+ uri: episode.sourceUri,
50
+ createdAt: episode.createdAt
51
+ };
52
+ }
53
+ }