@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
package/docs/llms.txt ADDED
@@ -0,0 +1,126 @@
1
+ # Niro (niro-cli with the local engine)
2
+
3
+ > Niro builds a code graph on the developer's own computer, and serves it to coding agents over MCP and to the developer through `niro ask`. These pages ship inside the @niroai/niro package. Pull request review and root cause analysis are features of hosted Niro, not of this package.
4
+
5
+ How an agent should use this index:
6
+
7
+ 1. Read this file once.
8
+ 2. Open only the page that matches the question.
9
+ 3. When the user pastes an error message, open reference-messages.md first.
10
+ 4. Never run `niro start`, `niro login` or `niro uninstall` on the user's behalf. Ask before `niro plan remove`.
11
+ 5. Every factual sentence in these pages has its source in an HTML comment beside it.
12
+
13
+ llms-full.txt holds every page below in one file.
14
+
15
+ ## Reference and help (most used)
16
+
17
+ - [reference-messages.md](reference-messages.md): every user-visible message with an answer, linked to its explanation
18
+ - [troubleshooting.md](troubleshooting.md): the first three checks, and where each kind of problem is answered
19
+ - [reference-mcp-tools.md](reference-mcp-tools.md): every MCP tool and its inputs, as the engine serves them
20
+ - [reference-cli.md](reference-cli.md): every niro command and option
21
+ - [reference-engine-commands.md](reference-engine-commands.md): the commands niro passes to the engine (ask, ui, env, route-rule and others)
22
+ - [reference-environment-variables.md](reference-environment-variables.md): every environment variable and its default
23
+ - [reference-config-files.md](reference-config-files.md): settings files and keys
24
+ - [reference-exit-codes.md](reference-exit-codes.md): what each exit code means
25
+ - [reference-limits.md](reference-limits.md): every size, time and count limit
26
+
27
+ ## FAQ
28
+
29
+ - [faq-install-and-setup.md](faq-install-and-setup.md): installing, the engine, the background watcher
30
+ - [faq-login-and-account.md](faq-login-and-account.md): signing in, accounts
31
+ - [faq-licence-and-plans.md](faq-licence-and-plans.md): line limits, the licence
32
+ - [faq-indexing.md](faq-indexing.md): a folder not added yet, building the graph, files left out
33
+ - [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md): known gaps in answers, by kind and by language
34
+ - [faq-assistants-and-mcp.md](faq-assistants-and-mcp.md): connecting agents, agents not using Niro
35
+ - [faq-worktrees-and-branches.md](faq-worktrees-and-branches.md): branches, worktrees, temporary projects
36
+ - [faq-privacy-and-security.md](faq-privacy-and-security.md): what is sent, masking, files never read
37
+ - [faq-performance.md](faq-performance.md): slow builds and answers, disk
38
+ - [faq-updates.md](faq-updates.md): upgrading
39
+ - [faq-uninstall.md](faq-uninstall.md): removing Niro from this computer: common questions
40
+ - [faq-offline.md](faq-offline.md): working without a network
41
+ - [faq-feedback-and-receipts.md](faq-feedback-and-receipts.md): the end-of-task line, feedback
42
+
43
+ ## Ways in
44
+
45
+ - [connect-overview.md](connect-overview.md): which ways of using Niro work today: coding agents, the terminal, review bots, CI, a shared server
46
+ - [connect-terminal.md](connect-terminal.md): niro ask, niro ui and other terminal use
47
+ - [connect-your-ai-assistant.md](connect-your-ai-assistant.md): connecting coding agents over MCP
48
+ - [connect-review-bots.md](connect-review-bots.md): review bots (not supported locally)
49
+ - [connect-web-agents.md](connect-web-agents.md): browser agents (not in a release yet; use hosted Niro)
50
+ - [connect-ci.md](connect-ci.md): build machines (partial)
51
+ - [connect-team-server.md](connect-team-server.md): a shared server (not in a release yet)
52
+ - [agent-claude-code.md](agent-claude-code.md): Claude Code
53
+ - [agent-codex.md](agent-codex.md): Codex
54
+ - [agent-claude-desktop.md](agent-claude-desktop.md): Claude Desktop
55
+ - [agent-cursor.md](agent-cursor.md): Cursor
56
+ - [agent-windsurf.md](agent-windsurf.md): Windsurf
57
+ - [agent-vscode.md](agent-vscode.md): VS Code (GitHub Copilot)
58
+ - [agent-gemini-cli.md](agent-gemini-cli.md): Gemini CLI
59
+ - [agent-copilot-cli.md](agent-copilot-cli.md): GitHub Copilot CLI
60
+ - [agent-factory.md](agent-factory.md): Factory (droid)
61
+ - [agent-goose.md](agent-goose.md): Goose
62
+ - [agent-opencode.md](agent-opencode.md): OpenCode
63
+ - [agent-cline.md](agent-cline.md): Cline
64
+ - [agent-kiro.md](agent-kiro.md): Kiro
65
+ - [agent-antigravity.md](agent-antigravity.md): Antigravity
66
+
67
+ ## How it works
68
+
69
+ - [how-the-graph-works.md](how-the-graph-works.md): what the graph holds, and how to read an answer
70
+ - [builds-and-updates.md](builds-and-updates.md): adding another folder (`niro init`), rebuilding a graph, the background watcher, files left out
71
+ - [worktrees-and-branches.md](worktrees-and-branches.md): one graph per folder and branch, temporary projects, clean-up
72
+ - [where-things-are-stored.md](where-things-are-stored.md): every file Niro writes
73
+ - [what-leaves-your-machine.md](what-leaves-your-machine.md): every upload, and the Data Processing Agreement in short
74
+ - [secrets-and-masking.md](secrets-and-masking.md): masking, files never opened
75
+ - [licence-and-plans.md](licence-and-plans.md): plans, line counting, the licence
76
+ - [coverage-audit-and-consent.md](coverage-audit-and-consent.md): the coverage audit and code sharing
77
+ - [configuring-a-folder.md](configuring-a-folder.md): telling Niro what the code does not say: env values, a service's address, route rules that connect calls between services
78
+ - [uninstall.md](uninstall.md): removing Niro from this computer, or only one folder or one coding agent
79
+
80
+ ## Where Niro fits
81
+
82
+ - [lifecycle-overview.md](lifecycle-overview.md): where Niro helps at each stage of work on code: plan, write, review, test, debug
83
+ - [lifecycle-plan-and-design.md](lifecycle-plan-and-design.md): blast radius before a change
84
+ - [lifecycle-write-code.md](lifecycle-write-code.md): agents asking the graph while coding
85
+ - [lifecycle-review.md](lifecycle-review.md): reviewing a branch
86
+ - [lifecycle-test.md](lifecycle-test.md): what a change reaches, which tests reach it
87
+ - [lifecycle-debug.md](lifecycle-debug.md): debugging with Niro: from an error to the code that throws it, its callers and its catches
88
+ - [lifecycle-onboarding.md](lifecycle-onboarding.md): learning a codebase
89
+ - [lifecycle-security-and-privacy.md](lifecycle-security-and-privacy.md): security review with Niro
90
+ - [playbook-debug-exception.md](playbook-debug-exception.md): an error message or stack trace to its thrower, callers and catches
91
+ - [playbook-debug-wrong-value.md](playbook-debug-wrong-value.md): who writes a table or field, which event delivered a value
92
+ - [playbook-debug-failing-service-call.md](playbook-debug-failing-service-call.md): caller, handler, address, two services on one route
93
+ - [playbook-debug-after-a-change.md](playbook-debug-after-a-change.md): what a change reaches, tests first
94
+ - [playbook-debug-config.md](playbook-debug-config.md): settings the code reads, where they are set, calls with no address
95
+ - [playbook-debug-slow-path.md](playbook-debug-slow-path.md): what a slow method calls and where it reads the database
96
+ - [playbook-change-safely.md](playbook-change-safely.md): callers before an edit, overloads, static imports
97
+ - [playbook-add-a-feature.md](playbook-add-a-feature.md): the interface to implement and existing implementations
98
+ - [playbook-review-a-change.md](playbook-review-a-change.md): one blast-radius call for a whole change
99
+ - [playbook-test-a-change.md](playbook-test-a-change.md): the tests that reach a change
100
+ - [playbook-onboard.md](playbook-onboard.md): services, routes, stores, events, types
101
+ - [playbook-data-and-events.md](playbook-data-and-events.md): readers and writers of a table, publishers and handlers of a topic
102
+ - [answer-shapes.md](answer-shapes.md): shorter tool answers: the `answer` input (exists, count, locations, names, match)
103
+ - [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md): how tokens, speed and accuracy are measured, and how to measure them on your own work
104
+ - [evaluate-what-niro-did.md](evaluate-what-niro-did.md): the end-of-task line, the call record, `niro impact` over 7 and 30 days, a do-it-yourself A/B
105
+
106
+ ## What is supported
107
+
108
+ - [supported-overview.md](supported-overview.md): computers, languages, and library counts per language
109
+ - [supported-c.md](supported-c.md)
110
+ - [supported-cpp.md](supported-cpp.md)
111
+ - [supported-csharp.md](supported-csharp.md)
112
+ - [supported-go.md](supported-go.md)
113
+ - [supported-java.md](supported-java.md)
114
+ - [supported-javascript.md](supported-javascript.md)
115
+ - [supported-kotlin.md](supported-kotlin.md)
116
+ - [supported-php.md](supported-php.md)
117
+ - [supported-python.md](supported-python.md)
118
+ - [supported-ruby.md](supported-ruby.md)
119
+ - [supported-rust.md](supported-rust.md)
120
+ - [supported-swift.md](supported-swift.md)
121
+ - [supported-typescript.md](supported-typescript.md)
122
+
123
+ ## Other
124
+
125
+ - [index.md](index.md): the start page for people
126
+ - [hosted-only.md](hosted-only.md): pull request review and root cause analysis (hosted Niro)
@@ -0,0 +1,108 @@
1
+ # Playbook: add a feature
2
+
3
+ **The question, in the user's words:** "I want to add a new required action (a step a user must complete after login). What do I implement, and which existing classes can I copy?"
4
+
5
+ **What you get at the end:** the interface to implement, its methods (with overloads), every existing implementation to copy from, the matching factory interface, and a yes or no on whether a pattern you expect already exists.
6
+ <!-- source: outputs on this page: niro-local 43cce717 as `niro-local ask` from /home/niraj/projects/github/keycloak at 968726fe66, scratch home, 2026-11-10 (scratchpad niro-cli-task-playbooks/runs/feat-*.txt); `niro ask` runs the same engine command (src/commands/engineRoutes.js:28) -->
7
+
8
+ Words used on this page:
9
+ - an **interface** is a list of methods a class promises to have;
10
+ - an **implementation** is a class that keeps that promise;
11
+ - a **subtype** is a class or interface below another one;
12
+ - an **overload** is one of several methods with the same name and different parameters;
13
+ - a **default method** is an interface method that already has a body, so a class need not write it.
14
+
15
+ ## The steps
16
+
17
+ ### 1. How big is the interface?
18
+
19
+ ```
20
+ niro ask get_class_structure class_fqn=org.keycloak.authentication.RequiredActionProvider answer=count
21
+
22
+ INTERFACE org.keycloak.authentication.RequiredActionProvider: 7 methods
23
+ extends org.keycloak.provider.Provider
24
+ 15 subtypes below it; ask without answer= for them
25
+ ```
26
+ <!-- source: runs/feat-01-count.txt (210 characters) -->
27
+
28
+ ### 2. Its methods
29
+
30
+ ```
31
+ niro ask get_class_structure class_fqn=org.keycloak.authentication.RequiredActionProvider answer=names
32
+
33
+ methods:
34
+ evaluateTriggers(RequiredActionContext)
35
+ getMaxAuthAge()
36
+ getMaxAuthAge(KeycloakSession)
37
+ initiatedActionCanceled(KeycloakSession, AuthenticationSessionModel)
38
+ initiatedActionSupport()
39
+ processAction(RequiredActionContext)
40
+ requiredActionChallenge(RequiredActionContext)
41
+ ```
42
+ <!-- source: runs/feat-02-names.txt (517 characters) -->
43
+
44
+ Note the two `getMaxAuthAge` overloads. Four of the seven are `default` methods, so a new class must write only `evaluateTriggers`, `requiredActionChallenge` and `processAction`.
45
+ <!-- source: keycloak server-spi-private/.../RequiredActionProvider.java:46, :58, :96, :104 (default), :70, :79, :86 (abstract) -->
46
+
47
+ ### 3. Existing implementations to copy
48
+
49
+ The full answer (no `answer`) lists the 15 subtypes with their files, and which methods each one implements:
50
+
51
+ ```
52
+ niro ask get_class_structure class_fqn=org.keycloak.authentication.RequiredActionProvider
53
+
54
+ extended or implemented by (15, up to 3 levels down):
55
+ org.keycloak.authentication.requiredactions.DeleteAccount (implements RequiredActionProvider) services/.../DeleteAccount.java:52
56
+ org.keycloak.authentication.requiredactions.UpdatePassword (implements RequiredActionProvider) services/.../UpdatePassword.java:60
57
+ org.keycloak.authentication.requiredactions.VerifyEmail (implements RequiredActionProvider) services/.../VerifyEmail.java:68
58
+ ...
59
+ methods implemented or overridden elsewhere (56 implementations):
60
+ ```
61
+ <!-- source: runs/feat-03-full.txt (15,214 characters) -->
62
+
63
+ This answer is large. Ask for it once, when you are choosing what to copy.
64
+
65
+ ### 4. The factory that goes with it
66
+
67
+ ```
68
+ niro ask get_class_structure class_fqn=org.keycloak.authentication.RequiredActionFactory answer=count
69
+
70
+ INTERFACE org.keycloak.authentication.RequiredActionFactory: 7 methods
71
+ extends org.keycloak.provider.ProviderFactory
72
+ 19 subtypes below it; ask without answer= for them
73
+ ```
74
+ <!-- source: runs/feat-05-factory.txt (216 characters) -->
75
+
76
+ ### 5. Does the pattern you expect already exist?
77
+
78
+ `answer=exists` answers yes or no with a count:
79
+
80
+ ```
81
+ niro ask code_grep pattern="implements RequiredActionProvider, RequiredActionFactory" answer=exists
82
+
83
+ yes: 12 matching lines in 12 files in the files searched so far
84
+ PARTIAL: the search stopped at its 1.5 s limit after 9653 of 11045 file(s) ...
85
+ ```
86
+ <!-- source: runs/feat-04-exists.txt -->
87
+
88
+ So one class often plays both roles. "In the files searched so far" and the PARTIAL line say the count is a floor. To search the rest, call again with the `continue_from` the answer gives, or pass a folder such as `path_pattern=services/`. Until an answer comes back without PARTIAL, treat the count as "at least".
89
+ <!-- source: runs/feat-04-exists.txt ("Call again with continue_from=9653"); niro-local docs/NIRO-LOCAL-ISSUES.md entry "2026-11-10: code_grep counts change with machine load, and a busy machine can give '0 matching lines ... PARTIAL'" (OPEN, committed f1a9fe59); scratchpad niro-cli-task-playbooks-check/reruns (claim check round 1: 59 of 59 graph-tool reruns byte-identical, 7 code_grep reruns differed under load 17 to 30) -->
90
+
91
+ ## Why the answer is complete, and where it is not
92
+
93
+ - **Subtypes are listed up to 3 levels down,** by the `extends` and `implements` the code declares.
94
+ - **Finding code by what it does** ("is there already a rate limiter") is not in this release: `find_reusable_code` is off. Search by name with `code_grep` and `list_types`.
95
+ <!-- source: runs/feat-03-full.txt ("up to 3 levels down"); docs/reference-mcp-tools.md ("Two tools are off in this release: find_reusable_code and find_known_issues") -->
96
+
97
+ ## What grep would do instead
98
+
99
+ `grep -rln "implements.*RequiredActionProvider"` finds 13 files. The graph lists 15 subtypes. The two extra are `VerifyUserProfile` (extends `UpdateProfile`) and `WebAuthnPasswordlessRegister` (extends `WebAuthnRegister`): they implement the interface through a parent class, so no line in their files names it.
100
+ <!-- source: `grep -rln --include=*.java "implements.*RequiredActionProvider\b\|implements RequiredActionProvider" .` = 13 files (Keycloak 968726fe66, 2026-11-10); runs/feat-03-full.txt (15 subtypes; VerifyUserProfile.java:45 and WebAuthnPasswordlessRegister.java:34 marked "extends") -->
101
+
102
+ ## Cost
103
+
104
+ What these steps cost depends on your code and your question. How Niro counts the size of its answers, and how to measure the cost on your own tasks, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
105
+
106
+ ## Related
107
+
108
+ [playbook-change-safely.md](playbook-change-safely.md), [playbook-onboard.md](playbook-onboard.md), [lifecycle-write-code.md](lifecycle-write-code.md).
@@ -0,0 +1,93 @@
1
+ # Playbook: change code safely
2
+
3
+ **The question, in the user's words:** "I want to change `KeycloakModelUtils.findUserByNameOrEmail` so it stops falling back to a username lookup. What depends on it?"
4
+
5
+ **What you get at the end:** how big the change is, every caller up to three levels, the places to check, and which callers are tests. This is the check to run before an edit; [playbook-debug-after-a-change.md](playbook-debug-after-a-change.md) is the same check after one.
6
+ <!-- source: outputs on this page: niro-local 43cce717 as `niro-local ask` from /home/niraj/projects/github/keycloak at 968726fe66, scratch home, 2026-11-10 (scratchpad niro-cli-task-playbooks/runs/chg-*.txt); `niro ask` runs the same engine command (src/commands/engineRoutes.js:28) -->
7
+
8
+ Words used on this page:
9
+ - the **blast radius** of a change is everything it can affect: what calls the changed code (upstream) and what it calls (downstream);
10
+ - an **overload** is one of several methods with the same name and different parameters;
11
+ - a **static import** lets a Java file call another class's static method with no class name in front, as `findUserByNameOrEmail(...)`.
12
+
13
+ In recorded agent sessions, this was the second most common use of Niro: 144 of 794 calls (18%) mapped callers before an edit (these recordings are mostly Niro's own development, labelled by hand by one agent, about plus or minus 10%).
14
+ <!-- source: scratchpad niro-cli-task-playbooks/TASKS.md (hand labels of 794 recorded calls; one labeller, about plus or minus 10%) -->
15
+
16
+ ## The steps
17
+
18
+ ### 1. How big is it?
19
+
20
+ ```
21
+ niro ask get_blast_radius method_fqn=org.keycloak.models.utils.KeycloakModelUtils.findUserByNameOrEmail answer=count
22
+
23
+ Blast radius for KeycloakModelUtils.findUserByNameOrEmail — 163 affected functions, risk: high (+4 in tests, not counted in risk) (upstream 30, downstream 137)
24
+ ```
25
+ <!-- source: runs/chg-10-count.txt (668 characters) -->
26
+
27
+ Upstream (what calls it) is what your change can break: 30 entries. Downstream (what it calls) is 137, but a change to this method's own behaviour does not change what those callees do.
28
+
29
+ ### 2. The callers, by name and depth
30
+
31
+ ```
32
+ niro ask get_blast_radius method_fqn=org.keycloak.models.utils.KeycloakModelUtils.findUserByNameOrEmail direction=upstream answer=names
33
+
34
+ upstream:
35
+ AbstractUsernameFormAuthenticator.getUserFromForm (depth 1)
36
+ AbstractUsernameFormAuthenticator.getUser (depth 2)
37
+ ...
38
+ ValidateUsername.authenticate (depth 1)
39
+ OrganizationAuthenticator.resolveUser (depth 1)
40
+ DefaultCIBALoginUserResolver.getUserFromLoginHint (depth 1)
41
+ BackchannelAuthenticationEndpoint.authorizeClient (depth 3)
42
+ AuthenticationManager.lookupUserForBruteForceLog (depth 1)
43
+ ResourceOwnerPasswordCredentialsGrantType.process (depth 3)
44
+ PassThroughAuthenticator.authenticate [test] (depth 1)
45
+ UsernameOnlyAuthenticator.authenticate [test] (depth 1)
46
+ [shown all 30 entries; ask without answer= for signatures and code]
47
+ ```
48
+ <!-- source: runs/chg-11-names.txt (2,403 characters, 30 entries) -->
49
+
50
+ So the change reaches the browser login form, direct grant (password) logins, X.509 logins, organization logins and CIBA (backchannel) logins. Those are the flows to test.
51
+
52
+ ### 3. The places, to open one by one
53
+
54
+ `answer=locations` gives `file:line` and the exact id of each caller, which `get_source_code` takes as it is. For the direct callers only, use `get_reverse_call_chain` (it lists direct callers and, with `depth`, the levels above).
55
+ <!-- source: docs/answer-shapes.md; docs/reference-mcp-tools.md (get_reverse_call_chain) -->
56
+
57
+ ### 4. Overloads are answered one by one
58
+
59
+ A short name that matches several methods is answered once per match when you give `answer`:
60
+
61
+ ```
62
+ niro ask get_reverse_call_chain method_fqn=ErrorResponse.error answer=count
63
+
64
+ ## ErrorResponse.error(String, Response.Status) (overload 1 of 2)
65
+ ErrorResponse.error has 100 callers.
66
+ ## ErrorResponse.error(String, Object[], Response.Status) (overload 2 of 2)
67
+ ErrorResponse.error has 3 callers.
68
+ ```
69
+ <!-- source: runs/chg-20-overloads.txt (667 characters) -->
70
+
71
+ ## Why the answer is complete, and where it is not
72
+
73
+ - **All direct callers are listed, including a bare call through a static import.** `OrganizationAuthenticator.resolveUser` calls `findUserByNameOrEmail(session, realm, username)` with no class name in front.
74
+ <!-- source: keycloak services/.../OrganizationAuthenticator.java:353 (bare call); runs/chg-11-names.txt (listed at depth 1) -->
75
+ - **"confidence: PARTIAL" on step 1** means the walk stopped at depth 3 with more callers beyond; it says how many entries were cut there. Ask `depth=4` or `depth=5` if the far end matters.
76
+ <!-- source: runs/chg-10-count.txt ("128 node(s) marked '[+N more beyond depth]'"); niro-local src/niro_local/mcp/impact.py:40-41 -->
77
+ - **Known gap: methods declared on a parent interface.** Asking about an implementation, or the declaring interface, can answer "0 callers" when callers use a child interface's name. Ask the name the callers use. See [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md).
78
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md entry "2026-11-10: a call to an interface method inherited from a parent interface lands on a stand-in, so the declaring method and its implementations read '0 callers, complete'" (OPEN, committed f1a9fe59); runs/chg-03-impl-full.txt and runs/chg-07-iface-loc.txt -->
79
+
80
+ ## What grep would do instead
81
+
82
+ - **Level 1 works:** `grep -rn "findUserByNameOrEmail("` gives 10 lines in 9 files: the declaration, 7 production calls and 2 test-provider calls. But `grep "KeycloakModelUtils.findUserByNameOrEmail"`, the obvious search, finds `OrganizationAuthenticator` only through its `import static` line (68), not the call itself (353), which has no class name in front.
83
+ - **Level 2 and 3 do not scale.** The level-1 callers include `authenticate`, `getUser` and `action`. In Keycloak, `grep -F "getUser("` matches 560 lines in 237 files, and `grep -F "action("` 827 lines in 205 files, most of them unrelated methods of the same name.
84
+ - **Overloads look the same to grep.** `grep "ErrorResponse.error("` gives 184 lines in 47 files with no way to split them by overload. The graph's caller files for the two overloads together are the same 47 files, so the lists agree, and the graph adds which overload each one calls.
85
+ <!-- source: Keycloak 968726fe66, 2026-11-10: `grep -rn --include=*.java "findUserByNameOrEmail(" .` (10 lines, 9 files; OrganizationAuthenticator.java:353 has no class prefix, :68 is `import static org.keycloak.models.utils.KeycloakModelUtils.findUserByNameOrEmail`); `grep -F` counts ("getUser(" 560 lines, 237 files; "action(" 827 lines, 205 files); `grep -rn --include=*.java "ErrorResponse.error(" .` 184 lines in 47 files; caller files from runs/eval-01-loc.txt and runs/eval-02-loc-all.txt = 47, `comm` of the two sorted lists empty both ways -->
86
+
87
+ ## Cost
88
+
89
+ What these steps cost depends on your code and your question. How Niro counts the size of its answers, and how to measure the cost on your own tasks, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
90
+
91
+ ## Related
92
+
93
+ [playbook-debug-after-a-change.md](playbook-debug-after-a-change.md), [playbook-test-a-change.md](playbook-test-a-change.md), [lifecycle-plan-and-design.md](lifecycle-plan-and-design.md).
@@ -0,0 +1,107 @@
1
+ # Playbook: data stores and events
2
+
3
+ **The questions, in the user's words:** "We are renaming a column of the `orders` table: what reads or writes it, in which services?" and "I am changing the payload of the `orders.placed` topic: who publishes it, and who consumes it?"
4
+
5
+ **What you get at the end:** every method that reads, writes or deletes a store, across services and through ORM repositories; and for a message topic, its publishers and handlers, plus the events that have only one side.
6
+ <!-- source: outputs on this page: niro-local 43cce717 from /home/niraj/projects/github/niro-coverage-corpus/java-mono (68 synthetic services and a main that calls them; niro-coverage-corpus/README.md), scratch home, 2026-11-10 (scratchpad niro-cli-task-playbooks/runs/data-10-orders.txt, de-*.txt); `niro ask` runs the same engine command (src/commands/engineRoutes.js:28) -->
7
+
8
+ Words used on this page: an **event** is a message one piece of code publishes on a named **topic** (or queue) and other code handles; a **broker** is the server that carries it (Kafka, RabbitMQ, Redis and others).
9
+
10
+ In recorded agent sessions (mostly Niro's own development, labelled by hand by one agent, about plus or minus 10%), agents asked data and event questions with text search: 10 of 21 calls were `code_grep` and 1 was `list_data_resources`. The tools below answer these directly.
11
+ <!-- source: scratchpad niro-cli-task-playbooks/TASKS.md (hand labels of 794 recorded calls) -->
12
+
13
+ ## A table across services
14
+
15
+ ```
16
+ niro ask get_data_resource_usage resource_fqn=orders
17
+
18
+ sql:table:orders
19
+ read by (4):
20
+ LedgerDao.openOrders
21
+ OrderRepository.findByStatus
22
+ OrderRepository.findLate
23
+ OrderStoreService.open
24
+ written by (2):
25
+ SharedTables.createOrder
26
+ OrderStoreService.save
27
+ deleted by (1):
28
+ OrderStoreService.remove
29
+ ```
30
+ <!-- source: runs/data-10-orders.txt (268 characters) -->
31
+
32
+ These are in three services: `main` (`SharedTables`, plain SQL), `jdbc` (`LedgerDao`, plain SQL) and `spring-data-jpa` (`OrderRepository` and `OrderStoreService`, through Spring Data). `findByStatus` is a derived query: its SQL comes from the method's name and the entity's `@Table(name = "orders")`, and no line of code names the table.
33
+ <!-- source: java-mono main/.../SharedTables.java:23 (INSERT INTO orders); services/jdbc/.../LedgerDao.java:54 (SELECT ... FROM orders); services/spring-data-jpa/.../OrderEntity.java:8 (@Table(name = "orders")), OrderRepository.java:10 (findByStatus), OrderStoreService.java:12-16; services/spring-data-jpa/EXPECTED.json (same five spring-data-jpa uses) -->
34
+
35
+ Then, for each method, `get_blast_radius method_fqn=... direction=upstream answer=names` gives what calls it.
36
+
37
+ **What grep would do instead:** `grep -rniw orders` prints 53 lines in the Java files, mostly route paths (`/api/orders`), host names (`orders-api`) and topic names. The SQL lines are in there, but `OrderStoreService.save` and `remove` are not: they call `repository.save(order)` and `repository.deleteById(id)`.
38
+ <!-- source: `grep -rniw "orders" java-mono --include=*.java | wc -l` = 53 (2026-11-10); OrderStoreService.java:14, :16 -->
39
+
40
+ ## A topic: who publishes and who handles
41
+
42
+ ```
43
+ niro ask get_event_producers_and_handlers name=invoices.created
44
+
45
+ rabbitmq:invoices.created [spring-amqp]
46
+ published by (1):
47
+ EventPublishers.invoiceCreated
48
+ handled by (1):
49
+ InvoiceListener.onInvoice
50
+ ```
51
+ <!-- source: runs/de-03-ph.txt (149 characters) -->
52
+
53
+ The publisher is in `main` (`rabbitTemplate.convertAndSend("invoices.created", ...)`) and the handler in `spring-amqp` (`@RabbitListener(queues = "invoices.created")`).
54
+ <!-- source: java-mono main/.../EventPublishers.java:55; services/spring-amqp/.../InvoiceListener.java:14 -->
55
+
56
+ ### A trap a text search shows you
57
+
58
+ ```
59
+ niro ask get_event_producers_and_handlers name=orders.placed
60
+
61
+ kafka:orders.placed [kafka-clients]
62
+ published by (1):
63
+ EventPublishers.orderPlaced
64
+ handled by (1):
65
+ OrderAuditConsumer.run
66
+ ```
67
+ <!-- source: runs/de-05-orders.txt -->
68
+
69
+ A text search shows a second line that looks like a publish: `TrapCaller.run` calls `outbox.send("orders.placed", "x")`. But `outbox` is a class of the project's own that happens to be called `KafkaTemplate`, not Spring's Kafka client. Niro recognises a publish by the type the call is made on, so it leaves this one out. An agent with only a text search has to read the class to rule it out; in the A/B (task p-07), the shell-only agents did, in both runs.
70
+ <!-- source: java-mono main/.../traps/TrapCaller.java:12, :20 ("Must not become a publish to orders.placed"); runs/ts-02-out.txt note ("A call is recognised by the TYPE of the thing it is called on"); scratchpad niro-cli-task-playbooks/ab/judged-p1/p-07-a.json and judged-p2/p-07-a.json (TrapCaller item FOUND) -->
71
+
72
+ ### And where Niro misses, today
73
+
74
+ The same topic has two more consumers that this release does not read: a Kafka Streams topology (`builder.stream("orders.placed")`) and a Camel route (`from("kafka:orders.placed?...")`). Both are recorded gaps. A text search for the topic name finds them, so for a payload change, run `code_grep pattern=orders.placed answer=locations` as well.
75
+ <!-- source: java-mono services/kafka-clients/.../OrderEnrichmentTopology.java:9; services/camel/.../BillingRoutes.java:11; niro-coverage-corpus/catalog/java.json rows java.messaging.kafka-streams.builder and java.messaging.camel.route-uris (status pending, measured missed) -->
76
+
77
+ ## Events with one side
78
+
79
+ ```
80
+ niro ask find_orphaned_events limit=8
81
+
82
+ 20 event(s) with only one side:
83
+ carts.recovered [MESSAGE_QUEUE, nats]
84
+ handled here, nothing publishes it
85
+ giftcards.issued [MESSAGE_PUBLISH, spring-kafka]
86
+ published here, nothing handles it
87
+ ...
88
+ ```
89
+ <!-- source: runs/de-02-orphans.txt -->
90
+
91
+ One side missing means one of three things, and the answer says so: the other side is outside this project, its library is not recognised, or the two sides name the event differently.
92
+ <!-- source: runs/de-02-orphans.txt (the explanatory paragraph) -->
93
+
94
+ ## Why the answer is complete, and where it is not
95
+
96
+ - **Stores and events are read from known libraries and forms.** Each language page lists them, see [supported-overview.md](supported-overview.md). A form not listed (like the two consumers above) is missing without a warning.
97
+ - **Topics are matched by name.** A topic name built at run time, or read from a setting Niro has no value for, cannot be matched.
98
+ - **An in-process event** (a framework's own event bus) never leaves its service, and the answer marks it so.
99
+ <!-- source: runs/de-01-events.txt ("An event marked in-process never leaves the program that sends it"); docs/how-the-graph-works.md -->
100
+
101
+ ## Cost
102
+
103
+ What these steps cost depends on your code and your question. How Niro counts the size of its answers, and how to measure the cost on your own tasks, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
104
+
105
+ ## Related
106
+
107
+ [playbook-debug-wrong-value.md](playbook-debug-wrong-value.md), [playbook-onboard.md](playbook-onboard.md), [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md).
@@ -0,0 +1,96 @@
1
+ # Playbook: "it broke after my change"
2
+
3
+ **The question, in the user's words:** "I changed how credentials are created and removed, and now something else fails. What does my change reach?"
4
+
5
+ **What you get at the end:** everything that calls the changed methods (up to the depth you ask), which of those are tests, the routes and other services on the way, and what the changed methods call in turn.
6
+ <!-- source: Keycloak outputs on this page: niro-local 43cce717 as `niro-local ask` from /home/niraj/projects/github/keycloak at 968726fe66, scratch home, 2026-11-10 (scratchpad niro-cli-task-playbooks/runs/brk-*.txt); java-mono outputs from niro-coverage-corpus/java-mono (runs/xs-05-blast.txt); `niro ask` runs the same engine command (src/commands/engineRoutes.js:28) -->
7
+
8
+ Words used on this page: the **blast radius** of a change is everything it can affect: the methods that call the changed code (**upstream**) and the methods it calls (**downstream**).
9
+
10
+ ## The steps
11
+
12
+ ### 1. Name every method you changed, in one call
13
+
14
+ `method_fqns` takes a list, and treats it as one change. Start with the count, to see how big it is:
15
+
16
+ ```
17
+ niro ask get_blast_radius method_fqns='["org.keycloak.models.jpa.JpaUserCredentialStore.createCredentialEntity","org.keycloak.models.jpa.JpaUserCredentialStore.removeCredentialEntity"]' answer=count
18
+
19
+ Blast radius for 2 methods — 46 affected functions, risk: high (+6 in tests, not counted in risk) (upstream 27, downstream 25)
20
+ confidence: PARTIAL | has_more: true — ... What is cut is only the far end of the chain: 22 node(s) marked "[+N more beyond depth]" have callers further out that were not walked.
21
+ [counts only; ask without answer= for the list]
22
+ ```
23
+ <!-- source: runs/brk-01-multi.txt (634 characters); method_fqns "Several methods analysed as ONE change, in one call" (docs/reference-mcp-tools.md, get_blast_radius) -->
24
+
25
+ "PARTIAL" here means the walk stopped at the depth you asked (3 by default), not that something was missed inside it.
26
+ <!-- source: runs/brk-01-multi.txt ("What is listed is correct. Every DIRECT dependent is listed"); niro-local src/niro_local/mcp/impact.py:40-41 (depth 1 to 5) -->
27
+
28
+ ### 2. List the names, upstream only
29
+
30
+ ```
31
+ niro ask get_blast_radius method_fqns='[...same two...]' direction=upstream answer=names
32
+
33
+ Blast radius for 2 methods — 21 affected functions, risk: high (+6 in tests, not counted in risk) (upstream 27)
34
+ upstream:
35
+ JpaUserCredentialStore.createCredential (depth 1)
36
+ UserCredentialManager.createStoredCredential (depth 2)
37
+ SubjectCredentialManagerCacheAdapter.createStoredCredential (depth 3)
38
+ PasswordCredentialProvider.createCredential (depth 3)
39
+ ...
40
+ CredentialModelTest.testCredentialCRUD [test] (depth 3)
41
+ ...
42
+ ResetOTP.authenticate (depth 3)
43
+ UserResource.removeCredential (depth 3)
44
+ JpaUserProvider.removeStoredCredential (depth 1)
45
+ [shown all 27 entries; ask without answer= for signatures and code]
46
+ ```
47
+ <!-- source: runs/brk-02-names.txt (2,231 characters, 27 entries) -->
48
+
49
+ This is the list to check against the failure. Entries marked `[test]` are the tests that already reach the change: run those first. `UserResource.removeCredential` is an admin REST method, so the change reaches the admin API.
50
+
51
+ ### 3. When the changed code is a route, other services count too
52
+
53
+ From the synthetic java-mono corpus, after a change to the `GET /api/shipments/{id}` handler:
54
+
55
+ ```
56
+ niro ask get_blast_radius method_fqn=com.example.shop.shipping.ShippingMain.shipment answer=names
57
+
58
+ Blast radius for ShippingMain.shipment — 3 affected functions, risk: low (upstream 3)
59
+ upstream:
60
+ ShippingMain.routing (depth 1)
61
+ ShippingMain.main (depth 2)
62
+ ApacheHttpClient5Calls.shipment over HTTP (depth 1)
63
+ ```
64
+ <!-- source: runs/xs-05-blast.txt (371 characters) -->
65
+
66
+ "over HTTP" marks a caller in another service: here `main`, which calls the route by its address. `get_impact_analysis http_path=/api/shipments/{param}` gives the same list starting from the route.
67
+ <!-- source: runs/xs-06-impact.txt -->
68
+
69
+ ### 4. Read only what the list points at
70
+
71
+ Each full entry carries `file:start-end`, so `get_source_code` or a ranged file read opens exactly that method. Ask for `answer=locations` when you want the places without the code.
72
+ <!-- source: runs/chg-03-impl-full.txt ("Layout: each method's line carries its <file>:<start>-<end>"); docs/answer-shapes.md -->
73
+
74
+ ## Why the answer is complete, and where it is not
75
+
76
+ - **Every direct caller is listed, and every caller up to the depth.** The calls through an interface are followed: `SubjectCredentialManagerCacheAdapter` is reached although the tests only name `credentialManager()`, an interface.
77
+ <!-- source: runs/brk-02-names.txt; keycloak tests/base/.../CredentialModelTest.java:56 (`user.credentialManager().createStoredCredential(otp2)`) -->
78
+ - **Callers through a value whose type the code does not state** are counted as "Not listed" and named, so you can read them.
79
+ <!-- source: docs/faq-wrong-or-missing-answers.md "Not listed: N call(s) ... on a receiver of unknown type" -->
80
+ - **A method declared on a parent interface** can show fewer callers than it has, in this release. See [faq-wrong-or-missing-answers.md](faq-wrong-or-missing-answers.md).
81
+ <!-- source: niro-local docs/NIRO-LOCAL-ISSUES.md entry "2026-11-10: a call to an interface method inherited from a parent interface lands on a stand-in, so the declaring method and its implementations read '0 callers, complete'" (OPEN, committed f1a9fe59) -->
82
+
83
+ ## What grep would do instead
84
+
85
+ - **One level costs one search per name.** `createCredentialEntity` has 2 direct callers; each of those has callers; at depth 3 there are 27 entries to find, so a grep route needs a search for each name it meets.
86
+ - **Common names explode.** Level 3 here includes `authenticate`, `action` and `createCredential`. In Keycloak, `grep -F "authenticate("` matches 108 lines in 79 files and `grep -F "action("` 827 lines in 205 files.
87
+ - **Interface calls do not name the class that runs.** In one of our Keycloak A/B sets, every item the shell-only agent missed was an implementation reached through an interface.
88
+ <!-- source: grep -rn --include=*.java -F counts on Keycloak 968726fe66, 2026-11-10 ("authenticate(" 108 lines in 79 files, "action(" 827 lines in 205 files); scratchpad niro-local-receipt-recheck/NATIVE-CHOICES.md ("Every one of the 21 c4 misses is 'Implementations of <Interface>.<method>'") -->
89
+
90
+ ## Cost
91
+
92
+ Full entries are much larger than names, so ask for names first and the full entries only where you need them. What these steps cost depends on your code and your question. How Niro counts the size of its answers, and how to measure the cost on your own tasks, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
93
+
94
+ ## Related
95
+
96
+ [playbook-change-safely.md](playbook-change-safely.md) (the same check before you edit), [playbook-test-a-change.md](playbook-test-a-change.md), [playbook-review-a-change.md](playbook-review-a-change.md).
@@ -0,0 +1,95 @@
1
+ # Playbook: debug config and environment
2
+
3
+ **The question, in the user's words:** "This call works on my machine and fails in staging. Where does its address come from, which settings does this service read, and does Niro know their values?"
4
+
5
+ **What you get at the end:** every setting a folder's code reads, where each is read, whether Niro has a value for it, and the lines in config files that set it, with secrets masked.
6
+ <!-- source: outputs on this page: niro-local 43cce717 from /home/niraj/projects/github/niro-coverage-corpus/java-mono (synthetic, placeholder credentials only: niro-coverage-corpus/README.md), scratch home, 2026-11-10 (scratchpad niro-cli-task-playbooks/runs/cfg-*.txt); `niro env`, `niro ask` and `niro route-rule` pass to the engine (src/commands/engineRoutes.js:28-33) -->
7
+
8
+ Words used on this page: a **setting** is a named value the code reads at run time, from an environment variable or a config file; a **base address** is the `scheme://host:port` a service is reached at.
9
+
10
+ ## The steps
11
+
12
+ ### 1. Which settings does the code read?
13
+
14
+ ```
15
+ niro env list --path main
16
+
17
+ BASE_URL http://localhost:8100 computed
18
+ shop.orders.base-url no value main/src/main/java/com/example/shop/main/http/RestTemplateCalls.java:15
19
+ ```
20
+ <!-- source: `niro-local env list --path main` in java-mono, 2026-11-10 -->
21
+
22
+ Each line is a setting, its value, and who set it ("computed" means Niro worked it out). `shop.orders.base-url` is read by `@Value("${shop.orders.base-url}")` at line 15, and Niro holds no value for it.
23
+ <!-- source: java-mono main/.../RestTemplateCalls.java:15; `niro env --help` ("list: name, where found, value, and who set it") -->
24
+
25
+ ### 2. Where is it set?
26
+
27
+ `code_grep` also searches config, build and deploy files, with values masked:
28
+
29
+ ```
30
+ niro ask code_grep pattern="base-url" answer=locations
31
+
32
+ 4 matching lines in 3 files
33
+ main/src/main/java/com/example/shop/main/http/RestTemplateCalls.java:15
34
+ main/EXPECTED.json:112
35
+ main/EXPECTED.json:168
36
+ main/src/main/resources/application.yml:5
37
+ ```
38
+ <!-- source: runs/cfg-10-key.txt (258 characters) -->
39
+
40
+ Reading the config lines themselves shows the value, and masks what looks like a secret:
41
+
42
+ ```
43
+ niro ask code_grep pattern="base-url|password" path_pattern=main/src/main/resources/ match_mode=regex
44
+
45
+ [{"file":".../main/src/main/resources/application.yml","matches":[
46
+ {"line":5,"text":" base-url: http://orders-api:8101"},
47
+ {"line":15,"text":" password: <MASK_SECRET_002>"}],"truncated":false}]
48
+ ```
49
+ <!-- source: runs/cfg-11-yml.txt; masking: docs/secrets-and-masking.md -->
50
+
51
+ In this run `application.yml` sets the value, but `niro env list` still said "no value". Give Niro the value for the environment you are debugging, so its links follow that environment:
52
+
53
+ ```
54
+ niro env set shop.orders.base-url=http://orders-api:8101
55
+ niro build
56
+ ```
57
+ <!-- source: runs/cfg-10-key.txt and `niro-local env list --path main` (2026-11-10, value in application.yml:5 not shown by env list); `niro env --help` ("set: add or change values: KEY=VALUE, repeatable"; "Passwords and tokens are refused and never stored") -->
58
+
59
+ Niro refuses to store passwords and tokens: a graph needs addresses and names, not secrets.
60
+ <!-- source: `niro-local env --help` first line ("Passwords and tokens are refused and never stored: a graph needs addresses and names.") -->
61
+
62
+ ### 3. Which calls have no address, or two possible targets?
63
+
64
+ ```
65
+ niro route-rule unconnected
66
+
67
+ 5 address(es) dialled that no service here answers on:
68
+ http://gift-cards-api:8113: 1 call(s) from java-mono/main; no service here declares their paths
69
+ ...
70
+ 1 call(s) name no address in the source, and no service here declares their path.
71
+ java-mono/main GET /{param}
72
+ ```
73
+ <!-- source: `niro-local route-rule unconnected` in java-mono, 2026-11-10 -->
74
+
75
+ "No service here answers" means the address points outside the indexed code, or the address is wrong. "Name no address" means the URL is built from a setting or a variable Niro has no value for. The failing-call playbook shows how one rule settles a route two services declare: [playbook-debug-failing-service-call.md](playbook-debug-failing-service-call.md).
76
+
77
+ ## Why the answer is complete, and where it is not
78
+
79
+ - **`niro env list` lists every setting the engine found the code reading.** It is the place to start, because it also says where each is read.
80
+ - **A value can be missing even when a config file sets it,** as above. Treat "no value" as "Niro has no value", not "nothing sets it", and check with `code_grep`.
81
+ - **Settings read through a name built at run time are not found.** The graph sees what the code states.
82
+ <!-- source: the run above; docs/how-the-graph-works.md "What it cannot see" -->
83
+
84
+ ## What grep would do instead
85
+
86
+ grep finds `shop.orders.base-url` too. It does not say which calls use it, whether two services answer the path, or which addresses no service answers, and it prints `password: CHANGEME` in plain text, where `code_grep` prints `<MASK_SECRET_002>`.
87
+ <!-- source: java-mono main/src/main/resources/application.yml:15 (placeholder CHANGEME); runs/cfg-11-yml.txt -->
88
+
89
+ ## Cost
90
+
91
+ The value of this playbook is the lists grep cannot make (unconnected calls, values Niro holds), not token savings. What these steps cost depends on your code and your question. How Niro counts the size of its answers, and how to measure the cost on your own tasks, is in [tokens-speed-and-accuracy.md](tokens-speed-and-accuracy.md).
92
+
93
+ ## Related
94
+
95
+ [configuring-a-folder.md](configuring-a-folder.md) (env values, base address, route rules), [secrets-and-masking.md](secrets-and-masking.md), [reference-engine-commands.md](reference-engine-commands.md).