@niroai/niro 0.16.0 → 0.18.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 (177) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +123 -302
  3. package/bin/niro.js +12 -1
  4. package/docs/agent-antigravity.md +37 -0
  5. package/docs/agent-claude-code.md +48 -0
  6. package/docs/agent-claude-desktop.md +47 -0
  7. package/docs/agent-cline.md +42 -0
  8. package/docs/agent-codex.md +45 -0
  9. package/docs/agent-copilot-cli.md +42 -0
  10. package/docs/agent-cursor.md +44 -0
  11. package/docs/agent-factory.md +42 -0
  12. package/docs/agent-gemini-cli.md +42 -0
  13. package/docs/agent-goose.md +42 -0
  14. package/docs/agent-kiro.md +37 -0
  15. package/docs/agent-opencode.md +37 -0
  16. package/docs/agent-vscode.md +45 -0
  17. package/docs/agent-windsurf.md +38 -0
  18. package/docs/answer-shapes.md +69 -0
  19. package/docs/builds-and-updates.md +68 -0
  20. package/docs/cloud-README.md +372 -0
  21. package/docs/configuring-a-folder.md +51 -0
  22. package/docs/connect-ci.md +24 -0
  23. package/docs/connect-overview.md +20 -0
  24. package/docs/connect-review-bots.md +17 -0
  25. package/docs/connect-team-server.md +12 -0
  26. package/docs/connect-terminal.md +49 -0
  27. package/docs/connect-web-agents.md +9 -0
  28. package/docs/connect-your-ai-assistant.md +59 -175
  29. package/docs/coverage-audit-and-consent.md +51 -0
  30. package/docs/evaluate-what-niro-did.md +271 -0
  31. package/docs/faq-assistants-and-mcp.md +122 -0
  32. package/docs/faq-feedback-and-receipts.md +33 -0
  33. package/docs/faq-indexing.md +127 -0
  34. package/docs/faq-install-and-setup.md +103 -0
  35. package/docs/faq-licence-and-plans.md +86 -0
  36. package/docs/faq-login-and-account.md +69 -0
  37. package/docs/faq-offline.md +34 -0
  38. package/docs/faq-performance.md +33 -0
  39. package/docs/faq-privacy-and-security.md +113 -0
  40. package/docs/faq-uninstall.md +47 -0
  41. package/docs/faq-updates.md +59 -0
  42. package/docs/faq-worktrees-and-branches.md +59 -0
  43. package/docs/faq-wrong-or-missing-answers.md +275 -0
  44. package/docs/hosted-only.md +33 -0
  45. package/docs/how-the-graph-works.md +47 -0
  46. package/docs/index.md +157 -0
  47. package/docs/licence-and-plans.md +72 -0
  48. package/docs/lifecycle-debug.md +48 -0
  49. package/docs/lifecycle-onboarding.md +32 -0
  50. package/docs/lifecycle-overview.md +77 -0
  51. package/docs/lifecycle-plan-and-design.md +44 -0
  52. package/docs/lifecycle-review.md +30 -0
  53. package/docs/lifecycle-security-and-privacy.md +35 -0
  54. package/docs/lifecycle-test.md +28 -0
  55. package/docs/lifecycle-write-code.md +35 -0
  56. package/docs/llms-full.txt +8015 -0
  57. package/docs/llms.txt +126 -0
  58. package/docs/playbook-add-a-feature.md +108 -0
  59. package/docs/playbook-change-safely.md +93 -0
  60. package/docs/playbook-data-and-events.md +107 -0
  61. package/docs/playbook-debug-after-a-change.md +96 -0
  62. package/docs/playbook-debug-config.md +95 -0
  63. package/docs/playbook-debug-exception.md +124 -0
  64. package/docs/playbook-debug-failing-service-call.md +119 -0
  65. package/docs/playbook-debug-slow-path.md +80 -0
  66. package/docs/playbook-debug-wrong-value.md +137 -0
  67. package/docs/playbook-onboard.md +95 -0
  68. package/docs/playbook-review-a-change.md +72 -0
  69. package/docs/playbook-test-a-change.md +73 -0
  70. package/docs/reference-cli.md +113 -0
  71. package/docs/reference-config-files.md +42 -0
  72. package/docs/reference-engine-commands.md +56 -0
  73. package/docs/reference-environment-variables.md +89 -0
  74. package/docs/reference-exit-codes.md +67 -0
  75. package/docs/reference-limits.md +75 -0
  76. package/docs/reference-mcp-tools.md +326 -0
  77. package/docs/reference-messages.md +180 -0
  78. package/docs/secrets-and-masking.md +48 -0
  79. package/docs/supported-c.md +130 -0
  80. package/docs/supported-cpp.md +157 -0
  81. package/docs/supported-csharp.md +211 -0
  82. package/docs/supported-go.md +258 -0
  83. package/docs/supported-java.md +226 -0
  84. package/docs/supported-javascript.md +223 -0
  85. package/docs/supported-kotlin.md +124 -0
  86. package/docs/supported-overview.md +89 -0
  87. package/docs/supported-php.md +157 -0
  88. package/docs/supported-python.md +224 -0
  89. package/docs/supported-ruby.md +162 -0
  90. package/docs/supported-rust.md +150 -0
  91. package/docs/supported-swift.md +133 -0
  92. package/docs/supported-typescript.md +220 -0
  93. package/docs/tokens-speed-and-accuracy.md +99 -0
  94. package/docs/troubleshooting.md +42 -0
  95. package/docs/uninstall.md +74 -0
  96. package/docs/what-leaves-your-machine.md +71 -0
  97. package/docs/where-things-are-stored.md +59 -0
  98. package/docs/worktrees-and-branches.md +55 -0
  99. package/package.json +5 -3
  100. package/src/commands/add-repo.js +5 -0
  101. package/src/commands/auditSend.js +67 -0
  102. package/src/commands/build.js +6 -0
  103. package/src/commands/docsSend.js +73 -0
  104. package/src/commands/engine.js +120 -0
  105. package/src/commands/engineRoutes.js +105 -0
  106. package/src/commands/guide.js +254 -0
  107. package/src/commands/init.js +16 -7
  108. package/src/commands/initLocal.js +96 -0
  109. package/src/commands/journalSend.js +47 -0
  110. package/src/commands/login.js +89 -12
  111. package/src/commands/mcp.js +22 -6
  112. package/src/commands/plan.js +99 -0
  113. package/src/commands/repoPush.js +33 -0
  114. package/src/commands/requestIntegration.js +38 -0
  115. package/src/commands/share.js +56 -0
  116. package/src/commands/start.js +451 -371
  117. package/src/commands/status.js +57 -0
  118. package/src/commands/takeover.js +6 -0
  119. package/src/commands/uninstall.js +180 -0
  120. package/src/commands/upgrade.js +38 -8
  121. package/src/commands/watch.js +420 -6
  122. package/src/index.js +174 -3
  123. package/src/lib/agentApi.js +32 -1
  124. package/src/lib/api.js +20 -6
  125. package/src/lib/auditUpload.js +293 -0
  126. package/src/lib/branchDrift.js +149 -0
  127. package/src/lib/choose.js +116 -0
  128. package/src/lib/cloudGuard.js +74 -0
  129. package/src/lib/credentials.js +2 -2
  130. package/src/lib/docsMarked.js +55 -0
  131. package/src/lib/docsState.js +213 -0
  132. package/src/lib/docsUpload.js +481 -0
  133. package/src/lib/engine.js +619 -0
  134. package/src/lib/folderSync.js +2 -1
  135. package/src/lib/graphCheck.js +40 -0
  136. package/src/lib/guide.js +293 -0
  137. package/src/lib/guideSearch.js +252 -0
  138. package/src/lib/integrationRequest.js +89 -0
  139. package/src/lib/journalUpload.js +147 -0
  140. package/src/lib/languages.js +129 -0
  141. package/src/lib/lease.js +375 -0
  142. package/src/lib/localBuild.js +285 -0
  143. package/src/lib/localEngine.js +210 -0
  144. package/src/lib/localOnboard.js +124 -0
  145. package/src/lib/localWorktrees.js +243 -0
  146. package/src/lib/machineCheck.js +58 -0
  147. package/src/lib/mcpClients.js +10 -1
  148. package/src/lib/migrationNotice.js +118 -0
  149. package/src/lib/modelFetch.js +153 -0
  150. package/src/lib/nestedOutput.js +23 -9
  151. package/src/lib/onboardingLog.js +34 -0
  152. package/src/lib/planUsage.js +165 -0
  153. package/src/lib/progressBar.js +46 -0
  154. package/src/lib/prompt.js +1 -1
  155. package/src/lib/redact.js +155 -0
  156. package/src/lib/release.js +33 -0
  157. package/src/lib/repoPush.js +495 -0
  158. package/src/lib/secret.js +1 -1
  159. package/src/lib/service.js +372 -63
  160. package/src/lib/shareCode.js +367 -0
  161. package/src/lib/shareExclusions.js +114 -0
  162. package/src/lib/shareFiles.js +129 -0
  163. package/src/lib/spinner.js +9 -5
  164. package/src/lib/watchDaemon.js +33 -10
  165. package/src/lib/watchState.js +12 -1
  166. package/src/lib/windowsPaths.js +67 -0
  167. package/src/mcp/lineCheck.js +382 -0
  168. package/src/mcp/lineName.js +92 -0
  169. package/src/mcp/localBackend.js +751 -0
  170. package/src/mcp/localMode.js +383 -0
  171. package/src/mcp/localSkill.js +189 -0
  172. package/src/mcp/server.js +610 -79
  173. package/src/mcp/setup.js +519 -131
  174. package/src/mcp/shellSearchHook.js +509 -0
  175. package/src/mcp/teardown.js +173 -91
  176. package/src/mcp/usingNiro.js +39 -0
  177. package/docs/working-on-branches.md +0 -162
@@ -0,0 +1,271 @@
1
+ # See and judge what Niro did for you
2
+
3
+ **You can check Niro's help yourself, in four ways:** read the line it prints at the end of each task, look at the record of which tools your agent asked, add up the last 7 and 30 days with `niro impact`, and run the same task with and without Niro. This page says what each number means, how it is worked out, and which numbers are estimates.
4
+
5
+ **An everyday comparison:** a taxi meter tells you the fare and the distance, and it is right about both. It does not know what the bus would have cost you. The end-of-task line is the same: its counts are measured, and its "instead of" figures are an estimate of the other route.
6
+
7
+ ## 1. The end-of-task line
8
+
9
+ At the end of a task your agent calls a tool, `mark_task_complete`, and copies the line it gets back into its reply. It looks like this:
10
+
11
+ ```
12
+ [NIRO-CLI] Listed the 4 module-detection paths that reach the changed premake reader · 2 calls instead of ~3 searches · ~1k tokens instead of ~5k · this session: ~39k tokens instead of ~96k
13
+ ```
14
+
15
+ **Example from a real session on Niro's own code. Your numbers will depend on your code and your tasks.** It is copied exactly as the engine printed it. Of the 38 end-of-task lines with a token saving recorded on one developer's computer over two days, it ranks 29th by the size of that saving: higher than most, not the largest.
16
+ <!-- source: the result of a real mark_task_complete call in a Claude Code session working on niro-local, 2026-11-10 03:53 UTC. Chosen from every [NIRO-CLI] line returned by mark_task_complete in this machine's Claude Code transcripts, 2026-11-10 00:19 to 2026-11-11 12:47 UTC (python3 -I receipts_mtc.py 4, scratchpad niro-cli-docs-methods-only/receipts-mtc.jsonl and ranked.txt): 85 lines, 38 of them with a task token pair. Ranked by the ratio of the two task token figures (here 5k / 1k = 5.0), it is 29th of 38 (76th percentile); counting the 47 lines with no token pair as no saving, it is 76th of 85 (89th percentile). Format: niro-local src/niro_local/mcp/receipt.py:9-16 (the three clauses, "[NIRO-CLI] <what it did> · <N calls instead of ~M searches> · <~X tokens instead of ~Yk>"), :204-208 ("this session: ...") -->
17
+
18
+ | Part | What it is | Measured or estimated |
19
+ |---|---|---|
20
+ | "Listed the 4 module-detection paths ..." | Your agent's own sentence about what Niro found, cut to 80 characters | Written by the agent |
21
+ | "2 calls" | How many Niro tool calls answered in this task | **Measured**, counted by the engine |
22
+ | "instead of ~3 searches" | How many extra searches and file reads the agent thinks it would have needed | **Estimated by the agent**: it types this number itself |
23
+ | "~1k tokens" | The size of every answer Niro returned in this task | **Measured characters**, turned into tokens at 2.09 characters a token |
24
+ | "instead of ~5k" | What finding the same things by hand would have cost | **Estimated** by the engine, as below |
25
+ | "this session: ..." | The same two token figures, added up over the session so far | Same as above; shown from the second priced task |
26
+ <!-- source: niro-local src/niro_local/mcp/receipt.py:12-15 (measured vs estimated, "There is no path through this module that prints an estimate without a tilde"), :33 (CHARS_PER_TOKEN = 2.09), :35 (MAX_CLAIM_CHARS = 80); src/niro_local/mcp/server.py:370-373 (Turn: "Two numbers are MEASURED here ... how many calls actually answered, and how many characters those answers contained"), :2209-2210 (niro_did, without_niro_extra_tool_calls typed by the agent), :533 (session total only after more than one priced turn) -->
27
+
28
+ **Where the 2.09 comes from.** It was measured against the model's own token counts, in Keycloak A/B transcripts, on results of more than 2,000 characters each. Over 69 Niro answers the median was 2.09 characters a token (middle half 1.83 to 2.25). Over 367 shell-tool results it was 2.10. So one rate fits both sides of the line.
29
+ <!-- source: niro-local src/niro_local/mcp/receipt.py:27-33; scratchpad niro-local-receipt-tokens/HOW-MEASURED-AND-VERDICT.md (69 answers median 2.09, quartiles 1.83 to 2.25; 367 native results median 2.10) -->
30
+
31
+ ### How "instead of ~Y" is estimated
32
+
33
+ The engine prices the by-hand route the way agents with only shell tools were measured to work on Keycloak: they search for the name they were asked about, then read about 40 lines around each place that matters, and almost never open a whole file. So for each task it counts:
34
+
35
+ - one text search per name the question asked about, at one output line per place the name appears (capped at 250 lines);
36
+ - one 40-line read for every place (`file:line`) an answer showed you; places in one file within 40 lines of each other count once;
37
+ - one more search for things a name search cannot reach, such as the classes that run when code calls an interface.
38
+ <!-- source: niro-local src/niro_local/mcp/by_hand.py:1-21 (the agreed method, Niraj 2026-11-09), :29-38 (READ_LINES = 40, median of 375 reads, quartiles 26/40/80; MAX_GREP_LINES = 250); scratchpad niro-local-receipt-recheck/NATIVE-CHOICES.md (sets c4 and c3, 99 runs) -->
39
+
40
+ **Only what you were shown is priced.** A page of an answer that was cut off adds nothing, and a short `answer=` form is priced for what it showed.
41
+ <!-- source: niro-local src/niro_local/mcp/by_hand.py:15-17; docs/usecases/answer-shapes.md rule 12 -->
42
+
43
+ **Honest limits of the estimate:**
44
+ - It is a model of a typical agent, not a replay of yours. An agent that reads whole files would have spent more; one that guessed the right file first would have spent less.
45
+ - An earlier version priced every named file in full. Checked against what shell-only agents really read on Keycloak, it was far too high, so it was replaced by the method above.
46
+ <!-- source: scratchpad niro-local-receipt-tokens/HOW-MEASURED-AND-VERDICT.md (set v17, whole-file pricing against the shell-only arm's real tokens) -->
47
+ - How it is checked: the line prices only the work Niro answered, so it is compared, in A/B runs, with what the shell-only session of the same task read, less what the Niro session still read with shell tools. In our A/B runs so far, added up over the tasks that printed a token figure, the two came close; for one task they can differ by several times either way. Read a single line's "instead of" as a rough order of size. More in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
48
+ <!-- source: scratchpad niro-cli-task-playbooks/AB-RESULTS.md "Receipt figures against measured tokens" (fix round 1); ab/receipt-adjusted.json (python3 -I ab/replay_receipts.py p1 p2) -->
49
+ - The "~3 searches" figure is the agent's own guess, and nothing checks it. It can be compared with an A/B run's call counts: the shell-only session's calls, against the Niro session's Niro calls and the shell calls it still made.
50
+ <!-- source: niro-local src/niro_local/mcp/server.py:2209-2210 (without_niro_extra_tool_calls typed by the agent); scratchpad niro-local-receipt-tokens/HOW-MEASURED-AND-VERDICT.md (calls replaced, worked from the two arms' call counts) -->
51
+
52
+ ### How the two token figures are made
53
+
54
+ **What the answers cost.** The engine adds up the characters of every Niro answer in the task, divides by the characters-a-token rate above, and rounds the result for the line.
55
+
56
+ **The by-hand estimate.** The engine looks only at the answers that showed you places (`file:line`). It prices one read of the lines around each place, counting nearby places in one file once, from each file's real size and line count. It adds one search for each name the question asked about, and one for what a name search cannot reach. It turns those characters into tokens at the same rate. An answer that showed no places, such as a count or a list of names, adds nothing.
57
+
58
+ **The calls and the agent's guess.** The line shows how many calls answered. It shows the agent's guess of searches only when the guess is more than the calls made.
59
+ <!-- source: niro-local src/niro_local/mcp/receipt.py:33 (CHARS_PER_TOKEN), :110-114 tokens_from_chars, :117-121 compact, :177-208 (calls clause only when searches_avoided > answered_calls); src/niro_local/mcp/by_hand.py:174-198 (reads, line_chars, read_chars) -->
60
+
61
+ **How the searches figure is kept.** The agent's number is stored with the task in the engine's record of the session (`niro journal`). It is not added up: the session total in the line covers tokens only.
62
+ <!-- source: niro-local src/niro_local/journal/store.py:114 (without_niro_extra_tool_calls column), :367-380 (Totals: answered_calls, tokens_returned, tokens_to_read_covered, priced_turns; no searches field); src/niro_local/mcp/server.py:464-498 (price adds tokens only) -->
63
+
64
+ **How the session total is kept.** Each task adds its two token figures to the session's running totals, in memory. A place or a search already priced earlier in the session is not priced again, because whoever made that read by hand would still have it. The total is shown from the second priced task on.
65
+ <!-- source: niro-local src/niro_local/mcp/server.py:374-376 (running totals in memory), :392-396 (priced places and searches), :464-498 (Turn.price: "leaves out reads and searches already priced this session"), :533 (session_priced_turns > 1) -->
66
+
67
+ ### When the line is shown, and when it is not
68
+
69
+ | What you see | Why |
70
+ |---|---|
71
+ | The line | Niro answered at least one call in this task |
72
+ | "N calls" with no "instead of" | The agent's guess was not more than the calls made, so no saving is claimed |
73
+ | No token pair | The by-hand estimate was not more than what Niro returned, or the two round to the same figure |
74
+ | No session total | It is the first priced task of the session, or the session grew past 20,000 files or 100,000 places, after which a total would be incomplete |
75
+ | "Not consulted: this turn used file reads instead" | The graph was there, and the agent searched the files itself |
76
+ | "Nothing to report: ..." | No Niro call answered in this task, so the agent should print nothing |
77
+ | Nothing at all | The line is switched off (`niro mcp receipt --off`), or the agent did not call `mark_task_complete` |
78
+ <!-- source: niro-local src/niro_local/mcp/receipt.py:177-208 (calls clause only when searches_avoided > answered_calls; token pair only when `comparison` shows a saving; `comparison` returns None when the compact figures are equal); src/niro_local/mcp/server.py:352-353 (MAX_SESSION_FILES 20,000, MAX_SESSION_PLACES 100,000), :523-524 (not_consulted), :2304-2313 ("Nothing to report"); docs/faq-feedback-and-receipts.md (niro mcp receipt --off) -->
79
+
80
+ **In Claude Code, a forgotten line is asked for once.** A Stop hook (a small command Claude Code runs when the agent is about to stop) checks the reply. If Niro answered and the line is missing, it asks the agent, once, to finish. It never prints anything itself, and it lets the agent stop if anything goes wrong.
81
+ <!-- source: src/mcp/lineCheck.js:1-26 -->
82
+
83
+ **The line is not saved.** It is shown once, in your agent's reply. See [faq-feedback-and-receipts.md](faq-feedback-and-receipts.md).
84
+ <!-- source: src/lib/receiptStore.js:1-15 -->
85
+
86
+ ## 2. The record of what your agent asked
87
+
88
+ `niro journal` lists the sessions the engine recorded and not yet sent, with each tool call, whether it worked, and how long it took:
89
+
90
+ ```
91
+ niro journal --limit 3
92
+
93
+ 9 session(s) waiting, 31 tool call(s) in total
94
+ adb7d35bb51e 5 call(s) started 2026-11-10T19:45:35+00:00 ended 2026-11-10T19:45:53+00:00
95
+ get_impact_analysis ok 122ms {"http_path": "/api/shipments/{id}", ...
96
+ resolve_name ok 19ms {"name": "ShippingMain.shipment"}
97
+ ...
98
+ find_api_endpoints ok 17ms {"limit": 20, "offset": 0, "path_pattern": "shipments"}
99
+ ...
100
+ ```
101
+ <!-- source: `niro-local journal --limit 3` on the scratch home used for the A/B of 2026-11-10 (a snapshot taken during the run, trimmed to 3 of the session's 5 calls; sessions of the synthetic java-mono corpus); `niro journal` passes to the engine (src/commands/engineRoutes.js:36, "What the MCP server was asked, waiting to be sent") -->
102
+
103
+ This is the place to see which tools your agent really uses, which fail, and which are slow. The record is sent to Niro (by the background watcher, or `niro journal-send`), and a sent session leaves this list. What it holds, and what it does not, is in [what-leaves-your-machine.md](what-leaves-your-machine.md).
104
+ <!-- source: src/commands/journalSend.js:1-12 ("in normal use the watcher calls the same library"); src/lib/planUsage.js:118 (JOURNAL_SENTENCE, "to improve Niro and to show you its value") -->
105
+
106
+ **The lines themselves are not kept, but their figures are.** Each task's counts, tokens and the agent's sentence stay on this computer after the session is sent, and `niro impact` adds them up (next section).
107
+ <!-- source: niro-local src/niro_local/journal/store.py turns table (niro_did, niro_helpfulness, task_outcome, searches_avoided on the task's row, kept after the upload; at most 20,000 rows), Journal.mark_sent (deletes only sessions and calls) -->
108
+
109
+ ## 3. What Niro did for you over time: `niro impact`
110
+
111
+ `niro impact` adds up the tasks on this computer for the last 7 and the last 30 days. It reads only the engine's record on this computer: nothing is sent, and no model is called.
112
+
113
+ Each window prints one figure per line, then the projects, then the good moments:
114
+
115
+ | Line | What it is | Measured or estimated |
116
+ |---|---|---|
117
+ | The record on this computer starts on ... | Shown only when the record starts after the window's first day, so "last 30 days" never quietly means fewer days. It sits directly under the window's heading | **Measured** |
118
+ | Tasks that used Niro: "N of M" | Tasks with at least one Niro answer, of all the tasks in the window | **Measured** |
119
+ | Number of calls Niro answered | The Niro answers in those tasks | **Measured** |
120
+ | Tokens used: "~X tokens instead of ~Y (estimated)" | X is what the answers cost; Y is the by-hand estimate of section 1, added up over the tasks that had both | X **measured**, Y **estimated** |
121
+ | Searches and file reads avoided: "~N" | The count the agents typed in `mark_task_complete`, added up. The kinds of call they named are kept in `--json` | **Estimated by the agents**; nothing checks them |
122
+ | Look-ups avoided: "~N" | The searches and file reads the graph answers stood for, less the Niro calls: the size of the work. See below | **Counted** |
123
+ | Round trips avoided: "at least ~M" | The searches your agent would have had to wait for one after another, plus reading the files, less the Niro calls: a floor on the waiting. See below | **Counted** |
124
+ | Answers by kind | The answers, grouped by the kind of question: impact check, caller lookup, trace of what a method calls, route and handler lookup, event trace, database lookup, type or name lookup, exception trace, text search, source read | **Measured** |
125
+ | Median answer time | The middle of the answer times recorded in the window | **Measured** |
126
+ | By project | The tasks, answers and tokens per project, by the project's name | As above |
127
+ | Good moments | The tasks with the best measured saving, tokens first and then calls, in the agents' own words, largest saving first: 3 for a window of up to 7 days, 10 for a longer one. A task rated not helpful or not used is never one | Chosen by numbers, never by the words |
128
+ | Some figures cover only tasks recorded since ... | Shown at the end of a window when a row covers fewer of its tasks, because some were recorded by an earlier version. The row itself shows its number as it is | **Measured** |
129
+ | Graph kept current | Per project, the files the graph holds and when it was last updated. Per window, the graph updates (full and incremental), the files they rebuilt, and the median update time | **Measured** |
130
+ <!-- source: niro-local src/niro_local/impact.py (module note; moments_for; TOOL_KINDS, ANSWER_KINDS; avoided_by_kind; _render_window, _tokens_line, _fewer_tasks_since; graph_updates, graph_current, _render_updates), src/niro_local/journal/store.py Journal.impact_groups, impact_moments (ORDER BY token_saving DESC, calls_saving DESC; niro_helpfulness NOT IN not_helpful, not_used), answer_tools, median_answer_ms; src/niro_local/build/state.py build_history -->
131
+
132
+ **An example.** This is `niro impact` exactly as it printed after five real tasks on two projects on one computer (four on Keycloak, one on a small Java project), unedited:
133
+
134
+ ```
135
+ What Niro did for you, from the record on this computer. Nothing here is sent anywhere.
136
+
137
+ Last 7 days (since 2026-11-04):
138
+ The record on this computer starts on 2026-11-11.
139
+ Tasks that used Niro: 5 of 5
140
+ Number of calls Niro answered: 7
141
+ Tokens used: ~12k tokens instead of ~60k (estimated)
142
+ Searches and file reads avoided: ~29
143
+ Look-ups avoided: ~238
144
+ Round trips avoided: at least ~5
145
+ Answers by kind: 3 caller lookups, 2 route and handler lookups, 1 impact check before a change, 1 text search.
146
+ Median answer time: 70 ms
147
+
148
+ By project:
149
+ keycloak: 4 task(s) with Niro, 5 answer(s), ~8k tokens instead of ~56k (estimated)
150
+ java-mono: 1 task(s) with Niro, 2 answer(s)
151
+
152
+ Good moments, in the agents' own words, largest saving first:
153
+ 2026-11-11 keycloak: Counted the callers of the error helper across 45 files (~5k tokens instead of ~47k, 2 call(s) instead of ~10 searches)
154
+ 2026-11-11 keycloak: Listed the 9 direct callers of the lookup, 2 of them in tests (~1k tokens instead of ~7k, 1 call(s) instead of ~6 searches)
155
+ 2026-11-11 keycloak: Found where the token lifespan constant is read (1 call(s) instead of ~3 searches)
156
+
157
+ Last 30 days (since 2026-10-12):
158
+ The record on this computer starts on 2026-11-11.
159
+ Tasks that used Niro: 5 of 5
160
+ Number of calls Niro answered: 7
161
+ Tokens used: ~12k tokens instead of ~60k (estimated)
162
+ Searches and file reads avoided: ~29
163
+ Look-ups avoided: ~238
164
+ Round trips avoided: at least ~5
165
+ Answers by kind: 3 caller lookups, 2 route and handler lookups, 1 impact check before a change, 1 text search.
166
+ Median answer time: 70 ms
167
+
168
+ By project:
169
+ keycloak: 4 task(s) with Niro, 5 answer(s), ~8k tokens instead of ~56k (estimated)
170
+ java-mono: 1 task(s) with Niro, 2 answer(s)
171
+
172
+ Good moments, in the agents' own words, largest saving first:
173
+ 2026-11-11 keycloak: Counted the callers of the error helper across 45 files (~5k tokens instead of ~47k, 2 call(s) instead of ~10 searches)
174
+ 2026-11-11 keycloak: Listed the 9 direct callers of the lookup, 2 of them in tests (~1k tokens instead of ~7k, 1 call(s) instead of ~6 searches)
175
+ 2026-11-11 keycloak: Found where the token lifespan constant is read (1 call(s) instead of ~3 searches)
176
+ 2026-11-11 java-mono: Listed the routes each service serves and which service calls which (2 call(s) instead of ~8 searches)
177
+
178
+ Graph kept current, per project:
179
+ java-mono: 155 files indexed in 1 folder(s), last updated 2026-11-11 10:43 UTC.
180
+ keycloak: 9,099 files indexed in 1 folder(s), last updated 2026-11-10 19:27 UTC.
181
+ typescript-mono: 366 files indexed in 1 folder(s), last updated 2026-11-10 19:28 UTC.
182
+ Graph updates:
183
+ Last 7 days: 1 graph update (1 full, 0 incremental), 155 files rebuilt, median update time 3.6 s.
184
+ Last 30 days: 1 graph update (1 full, 0 incremental), 155 files rebuilt, median update time 3.6 s.
185
+ Updates are recorded from 2026-11-11.
186
+ ```
187
+ <!-- source: a real run of niro-local a38ac9c6 (feat/impact-layout) over the keycloak and java-mono tasks, 2026-11-11; scratchpad niro-coverage-run/impact-work/real-impact-layout.txt -->
188
+
189
+ **How "look-ups avoided" is counted: the size of the work.** For each Niro answer that walks the graph (a call chain, the callers of a method, a blast radius or impact check, a route, handler, event or database lookup), the engine counts one search for each method the answer expanded or found, and one file read for each different file it covered. Each method and each file counts once in a task: when a second answer covers a file the first already covered, the file is not counted again, and asking the same question twice counts once. It then takes away the Niro calls themselves, because each of those is a call too, and never counts below 0 for one task. A text search or a source read adds nothing, because by hand it would be the same single call. The count is the work the answers stand for, not a claim that your agent would have made every one of those calls: an agent working by hand often stops early.
190
+ <!-- source: niro-local src/niro_local/mcp/round_trips.py (TOOLS; PerTask.add joins the receipt's covered files and counts each method and file once per task); src/niro_local/journal/store.py trips_avoided (MAX(0, methods_expanded + files_covered - graph_answers) per task, then summed); tests/test_round_trips.py -->
191
+
192
+ **A page counts only what it shows,** in both rows. When an answer is cut by `limit`, is a later page asked with `offset` or `from_line`, or is too long for one reply and shown a window of lines at a time, the engine counts only the files the page shows and the methods whose names it prints, the same way the end-of-task line prices only what was shown. For example, the callers of a method with `limit: 5` count the files of those 5 callers, not the files of every caller. An answer shortened with `answer=count` is not a page: it reports on everything the full answer covers, so it counts all of it.
193
+ <!-- source: niro-local src/niro_local/mcp/round_trips.py (cut, shown_part); src/niro_local/mcp/server.py answer (trips.paged or an offset: shown_part over the places _by_hand_route read off the page), _more_line and _fit (round_trips.cut); src/niro_local/mcp/shapes.py render (round_trips.cut when a listing shows fewer than it has); tests/test_round_trips.py (test_a_page_cut_by_limit_counts_only_the_callers_it_shows, test_a_window_of_lines_counts_only_what_the_window_shows, test_must_not_change_a_limit_above_the_list_or_a_count_counts_every_caller) -->
194
+
195
+ **How "round trips avoided" is counted: a floor on the waiting.** A round trip is one call your agent makes and then waits for. Working by hand, an agent can put the names of one level into one search (all the callers of a method, say), but it cannot search the next level before that search comes back, because it does not know the names yet. So a walk three levels deep takes at least three searches one after another, then one more round to read the files. For each Niro answer that added at least one method or file new to the task, the engine counts the deepest level the answer walked, plus 1 for reading the files, minus 1 for the Niro call itself. An answer that adds nothing new to the task counts -1: the Niro call was a round trip of its own, and it stood in for none. A list of a method's direct callers counts 1; a blast radius three levels deep counts 3; asking the same question again in the task counts -1; a later page of a list already paged in the task counts -1 too, or only the levels deeper than any page before it, since by hand the names of one level go into one search; a text search or a source read counts 0. Never below 0 for one task. It says "at least" because an agent working by hand often needs more than one search for a level, so the real number of waits is this or more. In the example above, the 5 is 1 (a list of direct callers) + 2 (a blast radius three levels deep, 3, then the callers of the same method asked again in the task, -1) + 1 (a list of callers that found none) + 1 (a list of routes); the text search counts 0.
196
+ <!-- source: niro-local src/niro_local/mcp/round_trips.py (levels_avoided: depth + READING_THE_FILES - THE_NIRO_CALL; Counted.depth; PerTask.add gives -THE_NIRO_CALL when nothing is new); src/niro_local/mcp/chains.py walk (level=spent + 1); src/niro_local/journal/store.py levels_avoided (MAX(0, levels_walked) per task, then summed); tests/test_round_trips.py (test_a_three_level_walk_counts_three_round_trips) -->
197
+
198
+ **The agents' words are checked again before they are shown.** They were masked when they were stored; `niro impact` masks them again, and replaces anything that looks like a file path, a piece of code or a network address with `[path]`, `[code]` or `[address]`. Only the project's name is shown.
199
+ <!-- source: niro-local src/niro_local/impact.py shown_words (mask_text, then redact/shapes.py hide_shapes: code spans, calls, statements, paths, IP addresses and host:port, dotted names, then render_claim); tests/test_impact.py test_a_secret_and_code_in_the_agents_words_are_not_printed -->
200
+
201
+ **Options:** `--days N` shows one window of N days (1 to 365) instead of both; `--project <name>` shows one project; `--json` prints the same report as JSON.
202
+ <!-- source: niro-local src/niro_local/cli.py _cmd_impact (1 to 365, upstream's ProjectImpactService MIN_DAYS and MAX_DAYS) -->
203
+
204
+ **How far back it goes.** The record keeps the newest 20,000 tasks, the newest 100,000 answers and the newest 1,000 graph updates. When the record starts after a window's first day, the report says on which day it starts, directly under the window's heading. Tasks recorded by an earlier version count in the numbers, with no words. When the look-ups, round trips or answers-by-kind rows cover fewer of the window's tasks because of them, each row shows its number as it is, and one line at the end of the window says "Some figures cover only tasks recorded since" the day they start. A graph update is recorded only when a build changed the graph: a build that failed, was refused, or found nothing changed is not one.
205
+ <!-- source: niro-local src/niro_local/journal/store.py MAX_KEPT_ROWS = 20_000, MAX_KEPT_ANSWERS = 100_000, _trim; src/niro_local/build/state.py MAX_BUILD_HISTORY = 1000; src/niro_local/build/builder.py Builder._record_history; impact.py _render_window ("The record on this computer starts on", only when its day is after the window's first day), _fewer_tasks_since ("Some figures cover only tasks recorded since"), _render_answers, _render_updates; src/niro_local/journal/store.py Journal.counts_recorded_from -->
206
+
207
+ **On a team server,** this release shows only what was recorded on your own computer. Answers from a teammate's shared server are recorded on that server.
208
+ <!-- source: niro-local feat/serve-http (not merged): mcp/connections.py, one journal session per connection in the server's journal.db -->
209
+
210
+ **`niro ab`, an account-wide on and off test, is hosted Niro only.** See [hosted-only.md](hosted-only.md).
211
+ <!-- source: src/index.js:478-480 ("`ab` switches the hosted MCP's A/B window"; left out when cloud is off); docs/reference-cli.md:86 -->
212
+
213
+ ## 4. Judge it yourself: a small A/B
214
+
215
+ The most honest test is to run the same task twice, once with Niro and once without, and compare.
216
+
217
+ ### How
218
+
219
+ 1. **Pick 3 to 5 real tasks** from your own work, with an answer you can check: "list every caller of X", "which tests reach Y", "who writes table Z".
220
+ 2. **Write down the right answer first,** by hand, so neither run grades itself.
221
+ 3. **Run each task twice in a fresh session:** once as you normally work, and once with Niro switched off for that session. In Claude Code, start the second run with `claude --strict-mcp-config --mcp-config '{"mcpServers":{}}'`, which starts it with no MCP servers.
222
+ 4. **Keep everything else the same:** the same model, the same prompt, the same agent version.
223
+ <!-- source: the same switches the measured A/B uses for its "without" arm (scratchpad niro-cli-task-playbooks/ab/bench.py session_cmd: --strict-mcp-config with an empty server list) -->
224
+
225
+ ### Which numbers to compare
226
+
227
+ | Number | Where to read it | What it tells you |
228
+ |---|---|---|
229
+ | Correctness: items found, items invented | Your answer key | Whether the answer was complete and true. This matters most |
230
+ | Cost, and tokens: cache writes, cache reads, output | Claude Code's `/cost`, or the `result` event of `claude -p --output-format stream-json` | What the run really cost |
231
+ | Tool calls | The transcript | How much searching and reading it did |
232
+ | Wall time | A clock, or the result event's `duration_ms` | How long you waited |
233
+ <!-- source: the fields bench.py reads from the result event (total_cost_usd, modelUsage cacheCreationInputTokens / cacheReadInputTokens / outputTokens, duration_ms): scratchpad niro-cli-task-playbooks/ab/bench.py parse_stream -->
234
+
235
+ Report all of them together. Cost alone hides why it moved: in long sessions, cache reads (the conversation re-read on every turn) are most of the tokens.
236
+ <!-- source: docs/tokens-speed-and-accuracy.md "How accuracy pays off over a long session" (cache reads were most of the tokens in both arms) -->
237
+
238
+ How we run ours, and what to keep in mind when reading the results, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
239
+
240
+ ### Check that an answer was complete
241
+
242
+ A list of callers can be checked against a text search. On Keycloak, `ErrorResponse.error` has two overloads (two methods with the same name and different parameters), and a grep for the name finds the calls to both. So ask for both:
243
+
244
+ ```
245
+ niro ask get_reverse_call_chain "method_fqn=org.keycloak.services.ErrorResponse.error(String, Response.Status)" answer=locations limit=300
246
+ # 100 callers, in 45 files
247
+
248
+ niro ask get_reverse_call_chain "method_fqn=org.keycloak.services.ErrorResponse.error(String, Object[], Response.Status)" answer=locations limit=300
249
+ # 3 callers, in 3 files
250
+
251
+ grep -rln --include=*.java "ErrorResponse.error(" .
252
+ # 47 files
253
+ ```
254
+
255
+ Keep the file part of each caller line, put the files of both answers in one sorted list, and compare it with grep's sorted list (`comm -3 a.txt b.txt` prints lines in only one of them). Here both lists had the same 47 files. A file only grep finds is a caller Niro missed, or a mention that is not a call; open it and see which.
256
+ <!-- source: scratchpad niro-cli-task-playbooks/runs/eval-02-loc-all.txt (overload 1: 100 callers, 45 files) and runs/eval-04-ov2.txt (overload 2: 3 callers in ErrorResponse.java, ClientResource.java, ClientsResource.java); union 47 files against `grep -rln --include=*.java "ErrorResponse.error(" .` (47 files); `comm` both ways empty (Keycloak 968726fe66, 2026-11-10) -->
257
+
258
+ **It does not always agree, and that is the point of checking.** For `JpaUserProvider.getUserByEmail`, Niro answered "0 callers" while a grep for `getUserByEmail(` found calls in many files. The callers use a child interface's name; asking `UserProvider.getUserByEmail` gives 17. That is a known problem, listed in [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md).
259
+ <!-- source: runs/chg-03-impl-full.txt (0 callers), runs/chg-07-iface-loc.txt (17); `grep -rn --include=*.java "getUserByEmail(" .` = 46 lines in 35 files -->
260
+
261
+ **For a class or interface,** compare `get_class_structure`'s subtypes with `grep -rln "implements <Name>"`. A grep cannot see a class that gets the interface through its parent class, so Niro listing more is expected; Niro listing fewer is worth reporting.
262
+ <!-- source: docs/playbook-add-a-feature.md (15 subtypes against 13 grep files, the 2 extra extend a parent class) -->
263
+
264
+ ## 5. Report a wrong or missing answer
265
+
266
+ Send the question, the answer, and what you expected (with the grep that showed it) to help@niro.ai. The known gaps are in [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md), and the feedback FAQ is [faq-feedback-and-receipts.md](faq-feedback-and-receipts.md).
267
+ <!-- source: docs/faq-feedback-and-receipts.md ("Email help@niro.ai"); docs/faq-wrong-or-missing-answers.md ("How do I report a wrong answer?") -->
268
+
269
+ ## Related
270
+
271
+ [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md), [answer-shapes.md](answer-shapes.md).
@@ -0,0 +1,122 @@
1
+ # FAQ: coding agents and MCP
2
+
3
+ ### Which coding agents does Niro support?
4
+ Fourteen:
5
+
6
+ - Claude Code
7
+ - Codex
8
+ - Claude Desktop
9
+ - Cursor
10
+ - Windsurf
11
+ - VS Code (GitHub Copilot)
12
+ - Gemini CLI
13
+ - GitHub Copilot CLI
14
+ - Factory (droid)
15
+ - Goose
16
+ - OpenCode
17
+ - Cline
18
+ - Kiro
19
+ - Antigravity
20
+
21
+ See [connect-your-ai-assistant.md](connect-your-ai-assistant.md).
22
+ <!-- source: src/mcp/setup.js:279-414 -->
23
+
24
+ ### My agent is not in the list.
25
+ Run `niro mcp install` and choose "Other (print the config)". Paste the block it prints into your agent's MCP settings.
26
+ <!-- source: src/mcp/setup.js:658-667 -->
27
+
28
+ ### "Unknown client: X"
29
+ The name after `--client` is not one Niro knows. `niro mcp install --list` shows the names.
30
+ <!-- source: src/mcp/setup.js:683, :3020 -->
31
+
32
+ ### "Failed to register MCP server. Is the Codex CLI installed?" (or the same for Gemini, Copilot, droid or Claude Code)
33
+ For these agents, Niro registers itself through the agent's own command. Install the agent's command first, then run `niro mcp install` again. The message gives the command to run by hand.
34
+ <!-- source: src/mcp/setup.js:775-777, :2123, :2620, :2645, :2671 -->
35
+
36
+ ### "Failed to write config ... Manually add to <path>" or "No config path known for <client>."
37
+ Niro could not write the agent's settings file. Add the block it prints by hand, at the path it names.
38
+ <!-- source: src/mcp/setup.js:2799, :2867 -->
39
+
40
+ ### I installed, but my agent shows no Niro tools.
41
+ Restart the agent. It reads its settings only when it starts.
42
+ <!-- source: src/mcp/setup.js:3071-3085 -->
43
+
44
+ ### My agent still searches files instead of asking Niro.
45
+ Only Claude Code gets hooks that remind it at every step. Other agents get instruction text, or nothing beyond the connection. Ask your agent to use the Niro tools, or start your request with "Use Niro to ...".
46
+ <!-- source: docs/usecases/impact-gate.md:155; src/mcp/setup.js:782-800, :2079-2100, :2436-2592 -->
47
+
48
+ ### A `.cursor/rules/niro.mdc` file appeared in my repository.
49
+ For Cursor, Niro writes its instructions as a rule in the folder where you ran `niro mcp install` or `niro upgrade`. Delete it, or add it to `.gitignore`, if you do not want it there.
50
+ <!-- source: src/mcp/setup.js:2079-2100; src/commands/upgrade.js:349-353 -->
51
+
52
+ ### What did install change in my agent's settings?
53
+ Each agent's page lists the files. Three agents also let Niro's tools run without asking each time:
54
+
55
+ - **Cursor:** an allowlist entry.
56
+ - **Kiro:** auto-approve for all of Niro's tools.
57
+ - **Codex:** approval mode "writes".
58
+ <!-- source: src/mcp/setup.js:445-503, :382-395, :2305-2318 -->
59
+
60
+ ### What does "Answered from the local graph on this machine (niro-local)." mean?
61
+ The answer came from the engine on your computer. Every answer starts with this line.
62
+ <!-- source: src/mcp/localBackend.js:189 -->
63
+
64
+ ### The Niro tool list is empty.
65
+ The engine did not start. Run `niro engine status` and `niro status` in a terminal to see why. Then restart the agent.
66
+ <!-- source: src/mcp/server.js:1266-1268 -->
67
+
68
+ ### "The local engine could not answer: <message>"
69
+ The engine stopped or failed on this question. The message says why. Run the same question with `niro ask` to see the full error.
70
+ <!-- source: src/mcp/server.js:1279 -->
71
+
72
+ ### "the local engine did not answer <method> within Nms" or "Niro MCP request timed out"
73
+ The question took too long: 30 seconds for one engine call, 2 minutes for one tool call. Ask a narrower question. Raise the tool limit with `NIRO_TOOL_TIMEOUT_MS`.
74
+ <!-- source: src/mcp/localBackend.js:183, :684; src/lib/pendingRequests.js:24, :64-68 -->
75
+
76
+ ### The first answer of every session takes about 20 seconds.
77
+ This happens when Niro's licence service cannot be reached. The engine waits for its licence. Known problem.
78
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:3617 (open) -->
79
+
80
+ ### My agent says "THIS FOLDER IS NOT INDEXED" and offers to index it.
81
+ The folder your agent is working in has no graph. Indexing stays on your computer. Say yes if you want Niro's help in that folder. It counts towards your line limit.
82
+ <!-- source: niro-local src/niro_local/offer.py:297-303, :409-414 -->
83
+
84
+ ### Will my agent run `niro start`, `niro login` or `niro uninstall` by itself?
85
+ No. The skill Niro installs tells it never to. It also tells the agent to ask you before it stops indexing a folder.
86
+ <!-- source: src/mcp/localSkill.js:8-90 -->
87
+
88
+ ### I work in two folders. Which one do the tools answer for?
89
+ The folder your agent's session started in. For the other folder, run `niro status` there to see whether it is indexed. Run `niro build <folder>` after editing it.
90
+ <!-- source: src/mcp/localMode.js:39 (RELEASE_WORKTREE_SENTENCE) -->
91
+
92
+ ### Claude Code shows "Niro impact check, before you edit this file". How do I turn it off?
93
+ It is advisory only. Turn it off with `touch ~/.niro/impact-gate-off`. Delete that file to turn it back on.
94
+ <!-- source: src/mcp/setup.js:1376-1405, :1512-1514; src/lib/impactLog.js:64 -->
95
+
96
+ ### Claude Code checks for a Niro line at the end of each task.
97
+ This is the end-of-task line. Turn it off with `niro mcp receipt --off`. See [faq-feedback-and-receipts.md](faq-feedback-and-receipts.md).
98
+ <!-- source: bin/niro.js:3-10; src/mcp/lineCheck.js:329-330; src/commands/mcp.js:79-90 -->
99
+
100
+ ### Can I use Niro with my agent on Windows?
101
+ Windows is supported, and the details are coming.
102
+ <!-- source: Niraj, 2026-11-10 -->
103
+
104
+ ### Cline does not show Niro after a restart.
105
+ Niro writes Cline's settings to the path Cline's users report. Cline's own documentation does not confirm it. Open Cline's MCP settings, and check where it keeps them.
106
+ <!-- source: src/mcp/setup.js:362-366 -->
107
+
108
+ ### Goose printed a block for me to paste.
109
+ Your Goose settings file is laid out in a way Niro does not change by itself. Paste the block into it.
110
+ <!-- source: src/mcp/setup.js:2693-2717 -->
111
+
112
+ ### "Niro is not set up in any AI assistant on this machine, so there is nothing to remove."
113
+ `niro mcp uninstall` found no agent with Niro in it.
114
+ <!-- source: src/mcp/teardown.js:663 -->
115
+
116
+ ### "Invalid --url" or "Refusing to use MCP server URL ..."
117
+ `--url` must start with `http://` or `https://`, with no spaces. It is for hosted Niro only.
118
+ <!-- source: src/mcp/setup.js:2897, :3036 -->
119
+
120
+ ### "MCP <label> wizard exited with code N"
121
+ The install or uninstall step failed. The lines above say why.
122
+ <!-- source: src/commands/mcp.js:43 -->
@@ -0,0 +1,33 @@
1
+ # FAQ: feedback and receipts
2
+
3
+ ### What is the "[NIRO-CLI]" line at the end of a task?
4
+ At the end of a task, your agent calls a tool, `mark_task_complete`. Niro answers with one line saying what its answers did in that task: how many calls answered (counted), how many searches the agent thinks they replaced (the agent's own estimate), and the tokens the answers cost against an estimate of the same work by hand. What each number means, and how each is worked out, is in [evaluate-what-niro-did.md](evaluate-what-niro-did.md). The agent copies the line into its reply. The line is not saved on your computer. What your agent wrote in that call (a summary of the task, and what Niro did) is part of the tool-usage record sent to Niro. See [what-leaves-your-machine.md](what-leaves-your-machine.md).
5
+ <!-- source: niro-local src/niro_local/mcp/server.py:2107; src/niro_local/journal/store.py:86-90, :121; src/lib/receiptStore.js:1-15 ("Nothing is stored locally to display it") -->
6
+
7
+ ### Why does the line not appear?
8
+ The agent must call `mark_task_complete` and copy the line. Claude Code checks for it at the end of each task. Other agents may skip it.
9
+ <!-- source: niro-local docs/HOW-TO.md:694-790; src/mcp/lineCheck.js -->
10
+
11
+ ### How do I turn the line off?
12
+ Run `niro mcp receipt --off`. Turn it on again with `--on`. To remove the tool altogether, set `NIRO_LOCAL_TASK_COMPLETE=0`.
13
+ <!-- source: src/commands/mcp.js:79-90; src/lib/receiptStore.js:33-35; niro-local src/niro_local/mcp/server.py:302 -->
14
+
15
+ ### "Nothing to report: no niro-local call answered this turn."
16
+ Niro was not asked anything during the task, so there is no line to show.
17
+ <!-- source: niro-local src/niro_local/mcp/server.py:2207-2215 -->
18
+
19
+ ### "The end-of-task Niro line is switched off on this machine"
20
+ You turned it off with `niro mcp receipt --off`.
21
+ <!-- source: src/mcp/localBackend.js:206-207 -->
22
+
23
+ ### Can I see past receipts?
24
+ Not the lines: each is shown once, in your agent's reply, and is not saved. Their figures are kept, and `niro impact` adds them up for the last 7 and 30 days, with a line per project. See [evaluate-what-niro-did.md](evaluate-what-niro-did.md). A `~/.niro/receipts` folder left by an earlier version is removed when you remove Niro from Claude Code (`niro mcp uninstall`), or by `niro uninstall`.
25
+ <!-- source: niro-local src/niro_local/impact.py and journal/store.py turns table (kept after upload); src/commands/engineRoutes.js (impact); src/lib/receiptStore.js:4-11, :64-75 (purge); src/mcp/teardown.js:396 (purge runs when Niro is removed from Claude Code); src/commands/uninstall.js:66, :157-159 (all of ~/.niro is deleted) -->
26
+
27
+ ### Two tool calls were counted as two sessions.
28
+ Known problem when two calls arrive at the same moment.
29
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:3663 (open) -->
30
+
31
+ ### How do I send feedback or ask for help?
32
+ Email help@niro.ai. The screen at the end of `niro start` also links the help site, GitHub and Discord.
33
+ <!-- source: help@niro.ai: Niraj, 2026-11-10; src/commands/start.js:131-136 -->
@@ -0,0 +1,127 @@
1
+ # FAQ: indexing and builds
2
+
3
+ Indexing means reading a folder's code and building its graph.
4
+
5
+ ### "This folder is not added yet. Run niro init to add it and build it."
6
+ `niro build` only rebuilds folders Niro already knows. Add this one with `niro init`.
7
+ <!-- source: src/commands/initLocal.js:53 -->
8
+
9
+ ### "Two folders were given (<a> and --path <b>). Give one."
10
+ You named a folder twice, once directly and once with `--path`. Give it once.
11
+ <!-- source: src/commands/initLocal.js:46 -->
12
+
13
+ ### "This folder is not indexed on this machine. Run niro start here to set it up."
14
+ Niro has no graph for this folder. On a computer that is already set up, `niro init` adds a folder. On a new computer, run `niro start`.
15
+ <!-- source: src/commands/status.js:97; src/index.js:490-502 -->
16
+
17
+ ### A file I know exists is missing from every answer.
18
+ It may be larger than 2 MB, which is the largest file Niro reads. `get_index_status` lists files left out for size. Raise the limit with `NIRO_LOCAL_MAX_FILE_BYTES`, then run `niro build`. Some answers say only "not found", with no word about the size, so check `get_index_status`.
19
+ <!-- source: niro-local src/niro_local/walk.py:79; src/niro_local/mcp/server.py (_render_status); niro-local docs/NIRO-LOCAL-ISSUES.md:3530 (open) -->
20
+
21
+ ### A file is listed as one "whose parse passed the 20 s time limit".
22
+ A file over 256 KB that takes longer than 20 seconds to read is left out. Raise the limit with `NIRO_LOCAL_PARSE_TIMEOUT_SECONDS`, then run `niro build`.
23
+ <!-- source: niro-local src/niro_local/build/parse_time_limit.py:44-57; src/niro_local/too_large.py:174 -->
24
+
25
+ ### "SKIPPED: N source file(s) larger than 2 MB ... were not indexed"
26
+ An answer may be missing something because these files were left out. The line names the first 5 of them, and says how to raise the limits.
27
+ <!-- source: niro-local src/niro_local/too_large.py:41, :164-182 -->
28
+
29
+ ### Which files and folders does Niro skip?
30
+ Niro skips:
31
+
32
+ - files your `.gitignore` covers (it honours `.gitignore` the way git does);
33
+ - build output folders;
34
+ - editor scratch files;
35
+ - links to other places on disk (symlinks);
36
+ - files in languages it does not read.
37
+ <!-- source: niro-local src/niro_local/mcp/source_tools.py:825-850; src/niro_local/gitindex.py; src/niro_local/walk.py -->
38
+
39
+ ### Minified or bundled JavaScript shows up as hundreds of methods.
40
+ A minified file is code squeezed onto a few lines for shipping. Niro filters many of them out, but one committed to the repository can still be read as code. Add it to `.gitignore` if it is generated. Mapping it back to its real source is not supported.
41
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:2849 (open); niro-local TODO.md:168 -->
42
+
43
+ ### Are HTML, Vue and Svelte files read?
44
+ Only their script blocks. The page markup itself is not read.
45
+ <!-- source: niro-local src/niro_local/languages.py, the comment above the javascript entry -->
46
+
47
+ ### My F#, Visual Basic or PowerShell code is not in the graph.
48
+ Niro has no reader for these languages. It counts F# and Visual Basic files in a build's summary, but nothing in them reaches the graph.
49
+ <!-- source: niro-local src/niro_local/profiles/local/unparsed-languages.json; coverage catalog powershell.json -->
50
+
51
+ ### Why are my tests in the graph?
52
+ Niro reads test code too, so you can see which tests reach a change. Hosted Niro sometimes leaves tests out, so counts can differ between the two.
53
+ <!-- source: niro-local TODO.md:3679 -->
54
+
55
+ ### "another niro-local was writing the graph, and this gave up (it waits at most 120 s ...)"
56
+ Two builds ran at once, and the second waited 2 minutes for the first. Run your build again when the first has finished. Raise the wait with `NIRO_LOCAL_BUILD_LOCK_WAIT`.
57
+ <!-- source: niro-local src/niro_local/cli.py:105-143; src/niro_local/build/lock.py:59 -->
58
+
59
+ ### A build of a very large repository crashed.
60
+ This is a known problem on some very large repositories (a "RecursionError"). Send the error to help@niro.ai.
61
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:528 (open) -->
62
+
63
+ ### The watcher's log says "Could not rebuild <folder>: ... Edits are not reaching the graph."
64
+ The background rebuild failed. Run `niro build` in that folder to see the full error. After you fix it, save any file and the watcher tries again.
65
+ <!-- source: src/lib/localBuild.js:172, :208-210 -->
66
+
67
+ ### An answer says "NOTE FROM niro-local: ACTION REQUIRED. The following file(s) were modified after the last index build".
68
+ Those files changed after the last build, so the graph may be out of date for them. The answer lists up to 20 of them. Read them directly. The watcher rebuilds them shortly.
69
+ <!-- source: niro-local src/niro_local/mcp/freshness.py:583-590, :346 -->
70
+
71
+ ### An answer says "niro-local is rewriting this folder's code graph right now".
72
+ A full build is running. For this one request, search the files (or use `code_grep` and `get_source_code`, which keep working), and ask again when the build ends. It does not mean "nothing found".
73
+ <!-- source: niro-local src/niro_local/mcp/freshness.py:309-334 -->
74
+
75
+ ### How long does a build take?
76
+ A full build of a repository of about 9,000 files was measured at about 103 seconds. Later rebuilds handle only what changed, and are much quicker.
77
+ <!-- source: niro-local TODO.md:189 -->
78
+
79
+ ### Does Niro run git, or read my history?
80
+ No. It reads three small git files: `.git/HEAD` (your branch), `.git/index` (which files git tracks) and `.git/config` (to tell copies of a repository apart). It never runs git, and never reads your history.
81
+ <!-- source: niro-local CLAUDE.md amendments 2026-11-03, 2026-11-04, 2026-11-07 -->
82
+
83
+ ### When does the graph update after I save a file?
84
+ About 3 seconds after the folder stops changing, if the background watcher is running. Check it with `niro status`.
85
+ <!-- source: src/lib/localBuild.js:36; src/commands/status.js:35-40 -->
86
+
87
+ ### A service has the wrong name, or a library shows up as a service.
88
+ Niro guesses which folders are separate services from build files and layouts, and sometimes guesses wrong. Two examples:
89
+
90
+ - some .NET projects are never treated as services;
91
+ - a Go library can be labelled a service.
92
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:612 (an ASP.NET Core project is never a service), :698 (a Go library is labelled a service) -->
93
+
94
+ `niro modules` shows what it decided. Fixing a wrong guess by hand is not supported yet.
95
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md:586, :607, :672, :1606, :3459 (open); src/commands/engineRoutes.js:34 -->
96
+
97
+ ### How does Niro find the services in a monorepo?
98
+ A monorepo is one repository holding several services. Niro uses each service's build file, and deployment files such as a Docker Compose file, to tell them apart. Some library modules in Cargo, Go, Gradle and .NET are not yet separated out. See [configuring-a-folder.md](configuring-a-folder.md).
99
+ <!-- source: niro-local docs/usecases/compose-addresses.md; niro-local docs/NIRO-LOCAL-ISSUES.md:2184, :2195 (open) -->
100
+
101
+ ### "the graph at <path> is damaged ... It is rebuilt from what was indexed."
102
+ The graph file was damaged, and the engine rebuilds it from its saved build state. Run the command it names.
103
+ <!-- source: niro-local src/niro_local/graph/sqlite_writer.py:520 -->
104
+
105
+ ### "the graph was written by an older major version of niro-local; run niro build"
106
+ After an upgrade, the graph needs one rebuild in the new format. Run `niro build`.
107
+ <!-- source: niro-local src/niro_local/graph/sqlite_writer.py:311-313 -->
108
+
109
+ ### "the graph ... was written by a newer major version of niro-local"
110
+ A newer Niro wrote this graph, and this older one will not change it. Run `niro upgrade`.
111
+ <!-- source: niro-local src/niro_local/graph/sqlite_writer.py:618-620 -->
112
+
113
+ ### "The niro-local home ... was last used by a newer niro-local ... Upgrade with: niro upgrade"
114
+ Same cause: a newer version used this folder. Run `niro upgrade`.
115
+ <!-- source: niro-local src/niro_local/registry.py:368-373 -->
116
+
117
+ ### When should I use `niro build --full`?
118
+ When you suspect the graph is wrong in a way a normal rebuild does not fix. It reads every file again. A normal rebuild gives the same graph, so you rarely need it.
119
+ <!-- source: src/index.js:517-527; niro-local CLAUDE.md (incremental must equal full) -->
120
+
121
+ ### My folder is in two projects. Which one does `niro build` build?
122
+ Both. Name one with `niro build --project <name>`.
123
+ <!-- source: src/index.js:517-527; niro-local src/niro_local/cli.py:300-306 -->
124
+
125
+ ### I deleted a folder. Is its graph still on disk?
126
+ Yes, for 14 days after Niro first saw it missing. Then it is removed. To remove it now, run `niro clean`. If you move the folder back, it is used again.
127
+ <!-- source: niro-local src/niro_local/cleanup.py:37-58; src/commands/engineRoutes.js:35 -->