noah-code 0.1.1__tar.gz → 0.2.1__tar.gz

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 (105) hide show
  1. {noah_code-0.1.1 → noah_code-0.2.1}/.github/workflows/ci.yml +19 -3
  2. {noah_code-0.1.1 → noah_code-0.2.1}/.github/workflows/release.yml +9 -3
  3. {noah_code-0.1.1 → noah_code-0.2.1}/PKG-INFO +62 -14
  4. {noah_code-0.1.1 → noah_code-0.2.1}/README.md +55 -8
  5. noah_code-0.2.1/docs/configuration.md +283 -0
  6. {noah_code-0.1.1 → noah_code-0.2.1}/docs/development.md +12 -1
  7. noah_code-0.2.1/docs/extensions.md +113 -0
  8. noah_code-0.2.1/docs/interactive-reference.md +148 -0
  9. noah_code-0.2.1/docs/releases/v0.2.0.md +52 -0
  10. noah_code-0.2.1/docs/releases/v0.2.1.md +36 -0
  11. {noah_code-0.1.1 → noah_code-0.2.1}/pyproject.toml +6 -5
  12. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/__init__.py +1 -1
  13. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/agent.py +275 -29
  14. noah_code-0.2.1/src/noah_code/agents.py +112 -0
  15. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/approvals.py +20 -4
  16. noah_code-0.2.1/src/noah_code/benchmark.py +140 -0
  17. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/cli.py +194 -4
  18. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/commands.py +41 -4
  19. noah_code-0.2.1/src/noah_code/composer.py +127 -0
  20. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/config.py +133 -7
  21. noah_code-0.2.1/src/noah_code/credentials.py +190 -0
  22. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/event_bridge.py +45 -8
  23. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/events.py +1 -0
  24. noah_code-0.2.1/src/noah_code/host.py +1290 -0
  25. noah_code-0.2.1/src/noah_code/llm.py +61 -0
  26. noah_code-0.2.1/src/noah_code/mcp_setup.py +308 -0
  27. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/permissions.py +124 -41
  28. noah_code-0.2.1/src/noah_code/providers.py +326 -0
  29. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/sessions.py +19 -4
  30. noah_code-0.2.1/src/noah_code/skills_setup.py +218 -0
  31. noah_code-0.2.1/src/noah_code/summarization.py +34 -0
  32. noah_code-0.2.1/src/noah_code/tool_output.py +97 -0
  33. noah_code-0.2.1/src/noah_code/tools/__init__.py +17 -0
  34. noah_code-0.2.1/src/noah_code/tools/git_tools.py +241 -0
  35. noah_code-0.2.1/src/noah_code/tools/lsp_tools.py +835 -0
  36. noah_code-0.2.1/src/noah_code/tools/media_tools.py +31 -0
  37. noah_code-0.2.1/src/noah_code/tools/process_tools.py +336 -0
  38. noah_code-0.2.1/src/noah_code/tools/question_tools.py +109 -0
  39. noah_code-0.2.1/src/noah_code/tools/task_tools.py +126 -0
  40. noah_code-0.2.1/src/noah_code/tools/web_tools.py +176 -0
  41. noah_code-0.2.1/src/noah_code/tools/workspace_tools.py +685 -0
  42. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/ui/console.py +11 -2
  43. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/ui/protocol.py +5 -1
  44. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/ui/textual.css +153 -29
  45. noah_code-0.2.1/src/noah_code/ui/textual_app.py +2246 -0
  46. noah_code-0.2.1/src/noah_code/usage.py +107 -0
  47. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_agent_security.py +11 -0
  48. noah_code-0.2.1/tests/test_agents.py +52 -0
  49. noah_code-0.2.1/tests/test_approvals.py +29 -0
  50. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_cli.py +49 -0
  51. noah_code-0.2.1/tests/test_composer.py +75 -0
  52. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_config.py +31 -0
  53. noah_code-0.2.1/tests/test_credentials.py +140 -0
  54. noah_code-0.2.1/tests/test_efficiency.py +105 -0
  55. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_event_bridge.py +14 -1
  56. noah_code-0.2.1/tests/test_git_tools.py +107 -0
  57. noah_code-0.2.1/tests/test_host.py +483 -0
  58. noah_code-0.2.1/tests/test_llm.py +75 -0
  59. noah_code-0.2.1/tests/test_lsp_tools.py +90 -0
  60. noah_code-0.2.1/tests/test_mcp_setup.py +108 -0
  61. noah_code-0.2.1/tests/test_permissions.py +152 -0
  62. noah_code-0.2.1/tests/test_process_tools.py +83 -0
  63. noah_code-0.2.1/tests/test_providers.py +119 -0
  64. noah_code-0.2.1/tests/test_question_tools.py +54 -0
  65. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_run_exit.py +46 -0
  66. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_sessions.py +2 -0
  67. noah_code-0.2.1/tests/test_skills_setup.py +69 -0
  68. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_summarization.py +2 -0
  69. noah_code-0.2.1/tests/test_task_tools.py +77 -0
  70. noah_code-0.2.1/tests/test_textual_tui.py +900 -0
  71. noah_code-0.2.1/tests/test_wave1_e2e.py +197 -0
  72. noah_code-0.2.1/tests/test_web_tools.py +86 -0
  73. noah_code-0.2.1/tests/test_workspace_tools.py +329 -0
  74. {noah_code-0.1.1 → noah_code-0.2.1}/uv.lock +13 -11
  75. noah_code-0.1.1/docs/configuration.md +0 -157
  76. noah_code-0.1.1/docs/extensions.md +0 -58
  77. noah_code-0.1.1/docs/interactive-reference.md +0 -96
  78. noah_code-0.1.1/src/noah_code/host.py +0 -715
  79. noah_code-0.1.1/src/noah_code/mcp_setup.py +0 -91
  80. noah_code-0.1.1/src/noah_code/skills_setup.py +0 -51
  81. noah_code-0.1.1/src/noah_code/tools/__init__.py +0 -6
  82. noah_code-0.1.1/src/noah_code/tools/git_tools.py +0 -44
  83. noah_code-0.1.1/src/noah_code/tools/workspace_tools.py +0 -269
  84. noah_code-0.1.1/src/noah_code/ui/textual_app.py +0 -1153
  85. noah_code-0.1.1/tests/test_host.py +0 -230
  86. noah_code-0.1.1/tests/test_permissions.py +0 -70
  87. noah_code-0.1.1/tests/test_textual_tui.py +0 -312
  88. noah_code-0.1.1/tests/test_workspace_tools.py +0 -145
  89. {noah_code-0.1.1 → noah_code-0.2.1}/.gitignore +0 -0
  90. {noah_code-0.1.1 → noah_code-0.2.1}/docs/releases/v0.1.0.md +0 -0
  91. {noah_code-0.1.1 → noah_code-0.2.1}/docs/releases/v0.1.1.md +0 -0
  92. {noah_code-0.1.1 → noah_code-0.2.1}/docs/security.md +0 -0
  93. {noah_code-0.1.1 → noah_code-0.2.1}/install.sh +0 -0
  94. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/__main__.py +0 -0
  95. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/custom_commands.py +0 -0
  96. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/macos_sandbox.py +0 -0
  97. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/snapshots.py +0 -0
  98. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/ui/__init__.py +0 -0
  99. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/updates.py +0 -0
  100. {noah_code-0.1.1 → noah_code-0.2.1}/src/noah_code/workspace.py +0 -0
  101. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_custom_commands.py +0 -0
  102. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_event_bridge_and_shell.py +0 -0
  103. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_installer.py +0 -0
  104. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_snapshots.py +0 -0
  105. {noah_code-0.1.1 → noah_code-0.2.1}/tests/test_updates.py +0 -0
@@ -34,6 +34,12 @@ jobs:
34
34
  - name: Install locked dependencies
35
35
  run: uv sync --locked --all-extras --dev
36
36
 
37
+ - name: Install ripgrep
38
+ run: |
39
+ sudo apt-get update
40
+ sudo apt-get install -y ripgrep
41
+ rg --version
42
+
37
43
  - name: Check lock file
38
44
  run: uv lock --check
39
45
 
@@ -41,7 +47,7 @@ jobs:
41
47
  run: uv run ruff check src tests
42
48
 
43
49
  - name: Test
44
- run: uv run pytest tests
50
+ run: uv run pytest tests -W error::pytest.PytestUnraisableExceptionWarning
45
51
 
46
52
  - name: Build distributions
47
53
  run: uv build --out-dir build-dist
@@ -76,8 +82,18 @@ jobs:
76
82
  - name: Install locked dependencies
77
83
  run: uv sync --locked --all-extras --dev
78
84
 
85
+ - name: Install ripgrep
86
+ run: |
87
+ if [ "${{ runner.os }}" = "Linux" ]; then
88
+ sudo apt-get update
89
+ sudo apt-get install -y ripgrep
90
+ else
91
+ HOMEBREW_NO_AUTO_UPDATE=1 brew install ripgrep
92
+ fi
93
+ rg --version
94
+
79
95
  - name: Run tests
80
- run: uv run pytest tests
96
+ run: uv run pytest tests -W error::pytest.PytestUnraisableExceptionWarning
81
97
 
82
98
  - name: Verify command entry point
83
99
  run: uv run noah --version
@@ -88,5 +104,5 @@ jobs:
88
104
  UV_TOOL_BIN_DIR: ${{ runner.temp }}/noah-bin
89
105
  run: |
90
106
  uv build --out-dir smoke-dist
91
- uv tool install --managed-python --python 3.12 --no-build --with 'nooa[mcp,tracing]==0.0.8' smoke-dist/*.whl
107
+ uv tool install --managed-python --python 3.12 --no-build --with 'nooa[mcp,tracing]' smoke-dist/*.whl
92
108
  "${UV_TOOL_BIN_DIR}/noah" --version
@@ -47,10 +47,16 @@ jobs:
47
47
  - name: Install locked dependencies
48
48
  run: uv sync --locked --all-extras --dev
49
49
 
50
+ - name: Install ripgrep
51
+ run: |
52
+ sudo apt-get update
53
+ sudo apt-get install -y ripgrep
54
+ rg --version
55
+
50
56
  - name: Run release checks
51
57
  run: |
52
58
  uv run ruff check src tests
53
- uv run pytest tests
59
+ uv run pytest tests -W error::pytest.PytestUnraisableExceptionWarning
54
60
  uv lock --check
55
61
 
56
62
  - name: Build wheel and source distribution
@@ -64,11 +70,11 @@ jobs:
64
70
  UV_TOOL_DIR: ${{ runner.temp }}/noah-tools
65
71
  UV_TOOL_BIN_DIR: ${{ runner.temp }}/noah-bin
66
72
  run: |
67
- uv tool install --managed-python --python 3.12 --no-build --with 'nooa[mcp,tracing]==0.0.8' dist/*.whl
73
+ uv tool install --managed-python --python 3.12 --no-build --with 'nooa[mcp,tracing]' dist/*.whl
68
74
  "${UV_TOOL_BIN_DIR}/noah" --version
69
75
 
70
76
  - name: Upload release distributions
71
- uses: actions/upload-artifact@v5
77
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
72
78
  with:
73
79
  name: python-package-distributions
74
80
  path: dist/
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: noah-code
3
- Version: 0.1.1
3
+ Version: 0.2.1
4
4
  Summary: Noah Code terminal coding agent, built on NVIDIA OO Agents (NOOA)
5
5
  Project-URL: Homepage, https://github.com/skundu42/noah-code
6
6
  Project-URL: Documentation, https://github.com/skundu42/noah-code#readme
@@ -21,10 +21,11 @@ Classifier: Topic :: Software Development
21
21
  Requires-Python: <3.14,>=3.12
22
22
  Requires-Dist: click>=8.1.0
23
23
  Requires-Dist: litellm<1.92.0,>=1.84.0
24
- Requires-Dist: nooa-cli==0.0.8
25
- Requires-Dist: nooa==0.0.8
24
+ Requires-Dist: nooa-cli==0.0.9
25
+ Requires-Dist: nooa==0.0.9
26
26
  Requires-Dist: packaging>=24.0
27
27
  Requires-Dist: pydantic>=2.5.0
28
+ Requires-Dist: pyyaml>=6.0.0
28
29
  Requires-Dist: rich>=13.0.0
29
30
  Requires-Dist: textual>=1.0.0
30
31
  Requires-Dist: tomli>=2.0.0; python_version < '3.11'
@@ -33,9 +34,9 @@ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
33
34
  Requires-Dist: pytest>=8.0.0; extra == 'dev'
34
35
  Requires-Dist: ruff>=0.8.0; extra == 'dev'
35
36
  Provides-Extra: mcp
36
- Requires-Dist: nooa[mcp]==0.0.8; extra == 'mcp'
37
+ Requires-Dist: nooa[mcp]==0.0.9; extra == 'mcp'
37
38
  Provides-Extra: tracing
38
- Requires-Dist: nooa[tracing]==0.0.8; extra == 'tracing'
39
+ Requires-Dist: nooa[tracing]==0.0.9; extra == 'tracing'
39
40
  Provides-Extra: tui
40
41
  Requires-Dist: textual>=1.0.0; extra == 'tui'
41
42
  Description-Content-Type: text/markdown
@@ -70,8 +71,12 @@ and seccomp support. You also need an LLM provider account such as OpenAI, Anthr
70
71
  ## Features
71
72
 
72
73
  - Read files, search with ripgrep, and inspect Git status, diffs, and history.
73
- - Edit files with anchored replacements, full rewrites, and concurrent-change detection.
74
- - Run permission-gated shell commands with timeouts and streamed output.
74
+ - Navigate definitions, implementations, references, symbols, hover types, and diagnostics through
75
+ lazily launched language servers plus an mtime-cached repository map.
76
+ - Edit files with anchored replacements or atomic multi-file patches with exact preimages,
77
+ rollback, immediate diagnostics, and concurrent-change detection.
78
+ - Run permission-gated shell commands with timeouts and streamed output, or own long-running
79
+ servers and watchers as bounded background jobs with cursor-based logs.
75
80
  - Follow repository instructions from `AGENTS.md`, `CLAUDE.md`, and `.noah-code/instructions.md`.
76
81
  - Switch between implementation-focused **build** mode and read-only **plan** mode.
77
82
  - Approve actions once or for a session with ordered `allow`, `ask`, and `deny` rules.
@@ -79,8 +84,16 @@ and seccomp support. You also need an LLM provider account such as OpenAI, Anthr
79
84
  - Work in an adaptive Atom One Dark cockpit, a classic console, or one-shot non-interactive mode.
80
85
  - Type `/` for a live-filtering command and configuration reference; press Enter to send.
81
86
  - Follow batched live tool output, then inspect compact execution records with `F2`.
87
+ - Review `/diff` in a keyboard-driven staged/worktree ledger with per-file patches, line deltas,
88
+ validation state, changed symbols, explicit revert, and checkpoint undo.
82
89
  - Resume workspace-scoped sessions with todos and automatic context compaction.
90
+ - Keep full oversized tool results privately while sending the model a focused, reopenable preview.
91
+ - Inspect token, prompt-cache, model-wait, and tool-output usage with `/tokens`; switch live
92
+ `fast`, `balanced`, and `deep` budgets with `/efficiency`.
83
93
  - Switch AI models between turns, with optional cross-repository defaults.
94
+ - Delegate research to nested **explore** and **general** subagents, or markdown agents in
95
+ `.noah-code/agents/`.
96
+ - Fetch pages and search the web, ask structured questions mid-turn, and attach `@files` or images.
84
97
  - Extend workflows with slash commands, opt-in skills, MCP servers, model selection, and tracing.
85
98
 
86
99
  ## Quick start
@@ -126,21 +139,56 @@ noah --version
126
139
  noah doctor .
127
140
  noah config show .
128
141
  noah update --check
142
+ noah benchmark .
129
143
  ```
130
144
 
145
+ Bring your own API key from inside the TUI by entering `/model`: choose the provider, paste the
146
+ key into the masked field, choose the model, then select its reasoning effort. Like OpenCode,
147
+ Noah saves provider credentials in `~/.local/share/noah-code/auth.json`; the directory is
148
+ owner-only and the file uses mode `0600`. API-key values are never written to Noah config,
149
+ repository, or session files. Set `XDG_DATA_HOME` to relocate the data directory.
150
+
151
+ Environment variables and the CLI remain available for scripts and headless use:
152
+
153
+ ```bash
154
+ export OPENAI_API_KEY="..." # or ANTHROPIC_API_KEY / OPENROUTER_API_KEY
155
+ noah providers list
156
+ noah providers add openai --model MODEL_NAME
157
+ noah .
158
+ ```
159
+
160
+ For reasoning models, choose `default`, `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`.
161
+ Provider and model support varies; `default` omits the parameter. You can set it in the guided
162
+ `/model` flow, switch it live with `/reasoning high`, or launch with:
163
+
164
+ ```bash
165
+ uv run noah --model openai/MODEL --reasoning-effort high .
166
+ ```
167
+
168
+ Custom OpenAI-compatible gateways, vLLM, LM Studio, Ollama, Azure OpenAI, Bedrock, Gemini, Groq,
169
+ Mistral, xAI, DeepSeek, Together AI, and Perplexity are also supported. See the
170
+ [provider configuration guide](docs/configuration.md#bring-your-own-api-provider).
171
+
131
172
  The package also installs `noah-code` and `nc` as equivalent entry points. Because `nc` commonly
132
- refers to netcat, `noah` or `noah-code` is recommended. Keep provider API keys in the environment
133
- or trusted NOOA user configuration, never in a repository or Noah Code session metadata.
173
+ refers to netcat, `noah` or `noah-code` is recommended. Keep provider API keys in Noah's private
174
+ auth file or environment, never in a repository or Noah Code session metadata.
134
175
 
135
- Inside a session, `/model MODEL` switches the active model immediately and remembers it when that
136
- session is resumed. It does not change other sessions. Use `/model --global MODEL` when the new
137
- model should also become the default for future sessions in every repository.
176
+ Inside a session, bare `/model` opens guided provider, API-key, model, and reasoning setup. `/model MODEL`
177
+ switches the active model immediately and remembers it when that session is resumed. It does not
178
+ change other sessions. Use `/model --global MODEL` when the new model should also become the
179
+ default for future sessions in every repository.
138
180
 
139
181
  The TUI keeps the conversation central and adds a session-and-plan rail on terminals at least
140
182
  110 columns wide. Tool output streams in a bounded activity panel and compacts after completion,
141
183
  keeping long runs responsive without deleting persisted session data. Press `F2` for activity
142
184
  details or `F3` for paginated conversation history.
143
185
 
186
+ The default `fast` profile uses compact NOOA trajectory rendering, bounded tool results, batched
187
+ repository inspection, cache-friendly turn-boundary context refresh, and lazy MCP connections. A
188
+ configured `lightweight_model` handles coding-session compaction; deterministic titles avoid an
189
+ otherwise unnecessary model request. Run `noah benchmark .` for the deterministic offline fixture
190
+ and `/tokens` for real provider-reported usage in the current run.
191
+
144
192
  ## Documentation
145
193
 
146
194
  - [Interactive interface and sessions](docs/interactive-reference.md)
@@ -163,7 +211,7 @@ noah update
163
211
  ## Development
164
212
 
165
213
  ```bash
166
- uv sync --extra dev
214
+ uv sync --extra dev --extra mcp --extra tracing
167
215
  uv run ruff check src tests
168
216
  uv run pytest tests
169
217
  uv build
@@ -28,8 +28,12 @@ and seccomp support. You also need an LLM provider account such as OpenAI, Anthr
28
28
  ## Features
29
29
 
30
30
  - Read files, search with ripgrep, and inspect Git status, diffs, and history.
31
- - Edit files with anchored replacements, full rewrites, and concurrent-change detection.
32
- - Run permission-gated shell commands with timeouts and streamed output.
31
+ - Navigate definitions, implementations, references, symbols, hover types, and diagnostics through
32
+ lazily launched language servers plus an mtime-cached repository map.
33
+ - Edit files with anchored replacements or atomic multi-file patches with exact preimages,
34
+ rollback, immediate diagnostics, and concurrent-change detection.
35
+ - Run permission-gated shell commands with timeouts and streamed output, or own long-running
36
+ servers and watchers as bounded background jobs with cursor-based logs.
33
37
  - Follow repository instructions from `AGENTS.md`, `CLAUDE.md`, and `.noah-code/instructions.md`.
34
38
  - Switch between implementation-focused **build** mode and read-only **plan** mode.
35
39
  - Approve actions once or for a session with ordered `allow`, `ask`, and `deny` rules.
@@ -37,8 +41,16 @@ and seccomp support. You also need an LLM provider account such as OpenAI, Anthr
37
41
  - Work in an adaptive Atom One Dark cockpit, a classic console, or one-shot non-interactive mode.
38
42
  - Type `/` for a live-filtering command and configuration reference; press Enter to send.
39
43
  - Follow batched live tool output, then inspect compact execution records with `F2`.
44
+ - Review `/diff` in a keyboard-driven staged/worktree ledger with per-file patches, line deltas,
45
+ validation state, changed symbols, explicit revert, and checkpoint undo.
40
46
  - Resume workspace-scoped sessions with todos and automatic context compaction.
47
+ - Keep full oversized tool results privately while sending the model a focused, reopenable preview.
48
+ - Inspect token, prompt-cache, model-wait, and tool-output usage with `/tokens`; switch live
49
+ `fast`, `balanced`, and `deep` budgets with `/efficiency`.
41
50
  - Switch AI models between turns, with optional cross-repository defaults.
51
+ - Delegate research to nested **explore** and **general** subagents, or markdown agents in
52
+ `.noah-code/agents/`.
53
+ - Fetch pages and search the web, ask structured questions mid-turn, and attach `@files` or images.
42
54
  - Extend workflows with slash commands, opt-in skills, MCP servers, model selection, and tracing.
43
55
 
44
56
  ## Quick start
@@ -84,21 +96,56 @@ noah --version
84
96
  noah doctor .
85
97
  noah config show .
86
98
  noah update --check
99
+ noah benchmark .
87
100
  ```
88
101
 
102
+ Bring your own API key from inside the TUI by entering `/model`: choose the provider, paste the
103
+ key into the masked field, choose the model, then select its reasoning effort. Like OpenCode,
104
+ Noah saves provider credentials in `~/.local/share/noah-code/auth.json`; the directory is
105
+ owner-only and the file uses mode `0600`. API-key values are never written to Noah config,
106
+ repository, or session files. Set `XDG_DATA_HOME` to relocate the data directory.
107
+
108
+ Environment variables and the CLI remain available for scripts and headless use:
109
+
110
+ ```bash
111
+ export OPENAI_API_KEY="..." # or ANTHROPIC_API_KEY / OPENROUTER_API_KEY
112
+ noah providers list
113
+ noah providers add openai --model MODEL_NAME
114
+ noah .
115
+ ```
116
+
117
+ For reasoning models, choose `default`, `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`.
118
+ Provider and model support varies; `default` omits the parameter. You can set it in the guided
119
+ `/model` flow, switch it live with `/reasoning high`, or launch with:
120
+
121
+ ```bash
122
+ uv run noah --model openai/MODEL --reasoning-effort high .
123
+ ```
124
+
125
+ Custom OpenAI-compatible gateways, vLLM, LM Studio, Ollama, Azure OpenAI, Bedrock, Gemini, Groq,
126
+ Mistral, xAI, DeepSeek, Together AI, and Perplexity are also supported. See the
127
+ [provider configuration guide](docs/configuration.md#bring-your-own-api-provider).
128
+
89
129
  The package also installs `noah-code` and `nc` as equivalent entry points. Because `nc` commonly
90
- refers to netcat, `noah` or `noah-code` is recommended. Keep provider API keys in the environment
91
- or trusted NOOA user configuration, never in a repository or Noah Code session metadata.
130
+ refers to netcat, `noah` or `noah-code` is recommended. Keep provider API keys in Noah's private
131
+ auth file or environment, never in a repository or Noah Code session metadata.
92
132
 
93
- Inside a session, `/model MODEL` switches the active model immediately and remembers it when that
94
- session is resumed. It does not change other sessions. Use `/model --global MODEL` when the new
95
- model should also become the default for future sessions in every repository.
133
+ Inside a session, bare `/model` opens guided provider, API-key, model, and reasoning setup. `/model MODEL`
134
+ switches the active model immediately and remembers it when that session is resumed. It does not
135
+ change other sessions. Use `/model --global MODEL` when the new model should also become the
136
+ default for future sessions in every repository.
96
137
 
97
138
  The TUI keeps the conversation central and adds a session-and-plan rail on terminals at least
98
139
  110 columns wide. Tool output streams in a bounded activity panel and compacts after completion,
99
140
  keeping long runs responsive without deleting persisted session data. Press `F2` for activity
100
141
  details or `F3` for paginated conversation history.
101
142
 
143
+ The default `fast` profile uses compact NOOA trajectory rendering, bounded tool results, batched
144
+ repository inspection, cache-friendly turn-boundary context refresh, and lazy MCP connections. A
145
+ configured `lightweight_model` handles coding-session compaction; deterministic titles avoid an
146
+ otherwise unnecessary model request. Run `noah benchmark .` for the deterministic offline fixture
147
+ and `/tokens` for real provider-reported usage in the current run.
148
+
102
149
  ## Documentation
103
150
 
104
151
  - [Interactive interface and sessions](docs/interactive-reference.md)
@@ -121,7 +168,7 @@ noah update
121
168
  ## Development
122
169
 
123
170
  ```bash
124
- uv sync --extra dev
171
+ uv sync --extra dev --extra mcp --extra tracing
125
172
  uv run ruff check src tests
126
173
  uv run pytest tests
127
174
  uv build
@@ -0,0 +1,283 @@
1
+ # Configuration, permissions, and updates
2
+
3
+ ## Configuration
4
+
5
+ Configuration is merged in this order, with later layers taking precedence:
6
+
7
+ 1. Built-in defaults.
8
+ 2. User config at `~/.config/noah-code/config.toml`.
9
+ 3. Project config at `.noah-code/config.toml`.
10
+ 4. `NOAH_CODE_*` environment variables.
11
+ 5. CLI flags.
12
+
13
+ ### First-run model setup
14
+
15
+ The first interactive `noah` launch asks for an AI model before starting the agent. Noah Code
16
+ saves that choice as the top-level `model` in `~/.config/noah-code/config.toml`, making it the
17
+ default for every repository. Enter a LiteLLM model name or an alias from the NOOA model registry.
18
+
19
+ An explicit `noah --model MODEL` on the first launch is saved without prompting. Project config,
20
+ `NOAH_CODE_MODEL`, and later `--model` flags still override the user default according to the
21
+ precedence above. Non-interactive commands such as `noah run`, `doctor`, and `config show` never
22
+ open the onboarding prompt.
23
+
24
+ Inside an interactive session, switch only the current session or replace the global default:
25
+
26
+ ```text
27
+ /model
28
+ /model openai/MODEL_NAME
29
+ /model --global anthropic/MODEL_NAME
30
+ ```
31
+
32
+ Bare `/model` opens a guided TUI flow: search for a provider, enter its API key in a masked
33
+ field, enter the model ID, and select reasoning effort. Noah saves the credential in
34
+ `~/.local/share/noah-code/auth.json`, using the same provider-keyed record shape as OpenCode.
35
+ The containing directory uses mode `0700` and the file uses mode `0600`. If the file cannot be
36
+ written, the key remains active only in the current Noah process and the TUI says so. Keys are
37
+ never written to Noah configuration or session metadata. `XDG_DATA_HOME` relocates the data root.
38
+
39
+ Model switches take effect between turns and are stored in the current session metadata, so a
40
+ resumed session continues with its most recently selected model. A session-only `/model MODEL`
41
+ does not change the user configuration or affect new sessions.
42
+
43
+ ### Bring your own API provider
44
+
45
+ Enter `/model` for the common provider → API key → model flow. Run `noah providers list` or open
46
+ `/providers` in the TUI for advanced, secret-free setup. Noah supports
47
+ LiteLLM's provider routing and includes guided presets for OpenAI, Anthropic Claude, OpenRouter,
48
+ Google Gemini, Groq, Mistral, xAI, DeepSeek, Together AI, Perplexity, Azure OpenAI, Amazon
49
+ Bedrock, and local Ollama.
50
+
51
+ For scripting, export credentials before starting Noah and select a provider/model:
52
+
53
+ ```bash
54
+ # OpenAI
55
+ export OPENAI_API_KEY="..."
56
+ noah providers add openai --model MODEL_NAME
57
+
58
+ # Anthropic Claude
59
+ export ANTHROPIC_API_KEY="..."
60
+ noah providers add anthropic --model MODEL_NAME
61
+
62
+ # OpenRouter
63
+ export OPENROUTER_API_KEY="..."
64
+ noah providers add openrouter --model PROVIDER/MODEL
65
+
66
+ # Google Gemini (GOOGLE_API_KEY is also accepted)
67
+ export GEMINI_API_KEY="..."
68
+ noah providers add gemini --model MODEL_NAME
69
+ ```
70
+
71
+ Use `--no-set-default` to print a one-launch command without changing Noah's global default.
72
+ Inside Noah, `/providers use openrouter PROVIDER/MODEL` switches the current session and saves the
73
+ new global default.
74
+
75
+ For vLLM, LM Studio, a company gateway, or another OpenAI-compatible API, create a secret-free
76
+ NOOA model alias:
77
+
78
+ ```bash
79
+ export COMPANY_LLM_API_KEY="..."
80
+ noah providers add custom \
81
+ --alias company-llm \
82
+ --model MODEL_ID \
83
+ --base-url https://llm.example.com/v1 \
84
+ --api-key-env COMPANY_LLM_API_KEY
85
+ ```
86
+
87
+ The alias is stored in `~/.config/nooa/llm_config.yaml` with mode `0600`. Only the environment
88
+ variable's name is stored. For an unauthenticated local endpoint, omit `--api-key-env`. You can
89
+ then use the alias anywhere a model is accepted: `noah --model company-llm .` or
90
+ `/model company-llm`.
91
+
92
+ Example user configuration:
93
+
94
+ ```toml
95
+ model = "gpt-4o-mini"
96
+ reasoning_effort = "default" # default, none, minimal, low, medium, high, or xhigh
97
+ lightweight_model = "gpt-4o-mini"
98
+ mode = "build"
99
+ max_iterations = 40
100
+ cell_timeout = 120
101
+ command_timeout = 60
102
+ max_output_chars = 16000
103
+
104
+ [efficiency]
105
+ profile = "fast" # "fast", "balanced", or "deep"
106
+ strategy = "lean" # "standard" is the comparison fallback
107
+ deterministic_titles = true
108
+ lazy_mcp = true
109
+ max_output_lines = 250
110
+ max_search_results = 100
111
+ max_file_results = 500
112
+ tool_output_retention_hours = 24
113
+
114
+ [lsp]
115
+ enabled = true
116
+ timeout_seconds = 5
117
+ max_symbols = 300
118
+ # Trusted user config may override a language server command:
119
+ # servers.python = ["basedpyright-langserver", "--stdio"]
120
+
121
+ [processes]
122
+ max_jobs = 8
123
+ max_runtime_seconds = 3600
124
+ max_buffer_chars = 64000
125
+ stop_grace_seconds = 2
126
+
127
+ [ui]
128
+ theme = "atom-one-dark"
129
+ frontend = "tui" # "tui" or "console"
130
+ markdown = true
131
+ stream_shell = true
132
+ show_reasoning = false
133
+
134
+ [summarization]
135
+ policy = "token_budget" # or "none"
136
+ trigger_ratio = 0.35
137
+ preserve_recent = 6
138
+ target_chars = 2500
139
+
140
+ [tracing]
141
+ enabled = true
142
+ viewer = true
143
+ # jsonl_dir = "~/.local/share/noah-code/traces"
144
+
145
+ [updates]
146
+ auto_install = true
147
+ interval_hours = 24
148
+ ```
149
+
150
+ Supported environment overrides include:
151
+
152
+ - `NOAH_CODE_MODEL`
153
+ - `NOAH_CODE_LIGHTWEIGHT_MODEL`
154
+ - `NOAH_CODE_REASONING_EFFORT`
155
+ - `NOAH_CODE_AUTO`
156
+ - `NOAH_CODE_SESSION_DIR`
157
+ - `NOAH_CODE_MODE`
158
+ - `NOAH_CODE_EFFICIENCY`
159
+ - `NOAH_CODE_UNSAFE_INPROCESS`
160
+ - `NOAH_CODE_AUTO_UPDATE`
161
+
162
+ Repository-controlled configuration cannot weaken the host trust boundary. Project config is
163
+ ignored for `auto_approve`, `efficiency`, `enabled_skills`, `lsp`, `mcp`, `permission_rules`,
164
+ `processes`, `session_dir`, `tracing`, `updates`, and `unsafe_inprocess_code_execution`. Put those
165
+ settings in trusted user config, the environment, or an explicit CLI flag. Language-server
166
+ overrides are user-only because they launch local executables.
167
+
168
+ A user-configured `permission_rules` array replaces the default rule array. Copy forward every
169
+ default you still want before adding overrides. Hard secret, destructive-shell, and plan-mode
170
+ gates remain enforced in code.
171
+
172
+ Inspect the resolved configuration from the CLI or inside an interactive session. `/config`
173
+ lists every nested path, while an optional path scopes the output. Values whose names look like
174
+ credentials are redacted.
175
+
176
+ ```bash
177
+ noah config show .
178
+ ```
179
+
180
+ ```text
181
+ /config
182
+ /config summarization
183
+ /config updates.auto_install
184
+ ```
185
+
186
+ Model and provider configuration follows NOOA conventions, including its model registry,
187
+ environment variables, and configuration under `~/.config/nooa/`. Provider strings not shown in
188
+ the guided list still pass through to LiteLLM, so additional supported services can be selected
189
+ with `--model PROVIDER/MODEL`.
190
+
191
+ Reasoning effort is passed through NOOA to LiteLLM only when it is not `default`. Supported values
192
+ are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`, but each provider/model may support
193
+ only a subset. Change the current session or the cross-repository default with:
194
+
195
+ ```text
196
+ /reasoning
197
+ /reasoning high
198
+ /reasoning --global low
199
+ ```
200
+
201
+ For headless launches use `--reasoning-effort high`, or add
202
+ `--reasoning-effort high` to `noah providers add ...` when saving a global model default.
203
+
204
+ ### Efficiency and model routing
205
+
206
+ `fast` is the default: at most 12 CodeAct iterations, 16,000 characters and 250 lines per
207
+ model-facing tool result, and lazy MCP attachment. `balanced` raises the live cap to 24 iterations
208
+ and its preview to 24,000 characters/400 lines. `deep` permits the configured `max_iterations` and
209
+ legacy-sized 80,000-character previews. Switch without restarting:
210
+
211
+ ```text
212
+ /efficiency
213
+ /efficiency balanced
214
+ /efficiency deep
215
+ ```
216
+
217
+ Oversized results are not discarded. Noah writes the exact output to a private cache file for the
218
+ configured retention period, returns a bounded head/tail preview, and gives the agent an output ID
219
+ for focused line-range retrieval. A truncated file preview is never returned as an editable Match
220
+ anchor.
221
+
222
+ Set `lightweight_model` to route compaction to a faster or cheaper model. If it is omitted, that
223
+ route follows live `/model` switches. Compaction starts at 35% of the active main model's context
224
+ window by default, preserves the six newest events, and writes a coding checkpoint covering the
225
+ objective, decisions, files, validation, blockers, and next steps.
226
+
227
+ ## Modes and permissions
228
+
229
+ | Mode | Behavior |
230
+ |------|----------|
231
+ | `build` | Reads are allowed; edits and shell commands follow permission rules and ask by default |
232
+ | `plan` | Reads are allowed; file edits and mutating shell commands are denied |
233
+
234
+ Switch modes with `--mode`, `/mode build`, or `/mode plan`. The active mode is stored with the
235
+ session.
236
+
237
+ Permission rules are evaluated in order, and the last matching rule wins. The default policy:
238
+
239
+ - Allows ordinary reads.
240
+ - Denies likely secrets, including `.env` variants, private keys, `.git` internals, and session
241
+ databases. `.env.example` remains readable.
242
+ - Asks before workspace edits, shell commands, web fetches, web searches, and subagents.
243
+ - Allows the question tool so the agent can pause for a structured choice.
244
+ - Denies `git push`, `git clean`, and `git reset --hard`.
245
+ - Keeps file tools inside the active workspace and asks before skill or MCP access.
246
+ - Denies plan-mode mutations regardless of broader allow rules. Plan mode may still run
247
+ read-only subagents.
248
+
249
+ `--auto` changes ask decisions to allow but never overrides an explicit deny. Compound shell
250
+ commands and mutating or unrecognized Git commands cannot be silently auto-approved.
251
+
252
+ ## Installation and updates
253
+
254
+ The README executes the checked-in bootstrapper directly from GitHub. From a local clone, run the
255
+ same installer with:
256
+
257
+ ```bash
258
+ sh install.sh
259
+ ```
260
+
261
+ Installs created by the one-line command check PyPI at most once every 24 hours and install newer
262
+ Noah Code releases through uv. When an update is installed, Noah exits before starting the task
263
+ so it cannot mix old and new runtime modules. Rerun the command to continue on the new version.
264
+
265
+ ```bash
266
+ # Check without changing the installation
267
+ noah update --check
268
+
269
+ # Update immediately
270
+ noah update
271
+ ```
272
+
273
+ Disable automatic installation from trusted user configuration or the environment:
274
+
275
+ ```toml
276
+ [updates]
277
+ auto_install = false
278
+ interval_hours = 24
279
+ ```
280
+
281
+ ```bash
282
+ export NOAH_CODE_AUTO_UPDATE=0
283
+ ```
@@ -5,7 +5,7 @@
5
5
  Install the development environment and run the local checks:
6
6
 
7
7
  ```bash
8
- uv sync --extra dev
8
+ uv sync --extra dev --extra mcp --extra tracing
9
9
  uv run ruff check src tests
10
10
  uv run pytest tests
11
11
  uv build
@@ -13,6 +13,17 @@ uv build
13
13
 
14
14
  The default test suite is hermetic and does not require network access or provider keys.
15
15
 
16
+ Run the deterministic efficiency fixture without making provider calls:
17
+
18
+ ```bash
19
+ uv run noah benchmark .
20
+ uv run noah benchmark . --json
21
+ ```
22
+
23
+ It compares standard and lean NOOA trajectory rendering, then measures the configured managed
24
+ preview against a fixed high-volume tool result. The report uses a transparent four-characters-
25
+ per-token estimate; use `/tokens` during a real session for provider-reported usage.
26
+
16
27
  ## CI
17
28
 
18
29
  GitHub Actions runs the complete test suite on Python 3.12 and 3.13, plus platform smoke tests on