noah-code 0.2.2__tar.gz → 0.2.3__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 (138) hide show
  1. {noah_code-0.2.2 → noah_code-0.2.3}/.github/workflows/ci.yml +16 -0
  2. {noah_code-0.2.2 → noah_code-0.2.3}/.gitignore +3 -0
  3. noah_code-0.2.3/.pre-commit-config.yaml +8 -0
  4. {noah_code-0.2.2 → noah_code-0.2.3}/PKG-INFO +15 -11
  5. {noah_code-0.2.2 → noah_code-0.2.3}/README.md +12 -9
  6. {noah_code-0.2.2 → noah_code-0.2.3}/docs/configuration.md +18 -7
  7. {noah_code-0.2.2 → noah_code-0.2.3}/docs/development.md +20 -9
  8. {noah_code-0.2.2 → noah_code-0.2.3}/docs/extensions.md +16 -4
  9. {noah_code-0.2.2 → noah_code-0.2.3}/docs/interactive-reference.md +54 -12
  10. {noah_code-0.2.2 → noah_code-0.2.3}/docs/releases/v0.1.1.md +1 -1
  11. {noah_code-0.2.2 → noah_code-0.2.3}/docs/releases/v0.2.0.md +3 -3
  12. noah_code-0.2.3/docs/releases/v0.2.3.md +50 -0
  13. {noah_code-0.2.2 → noah_code-0.2.3}/pyproject.toml +29 -2
  14. noah_code-0.2.3/src/noah_code/__init__.py +3 -0
  15. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/__main__.py +1 -1
  16. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/agent.py +222 -42
  17. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/agents.py +41 -17
  18. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/approvals.py +15 -2
  19. noah_code-0.2.3/src/noah_code/budget.py +230 -0
  20. noah_code-0.2.3/src/noah_code/checkpoints.py +186 -0
  21. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/cli.py +285 -35
  22. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/commands.py +96 -22
  23. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/config.py +79 -9
  24. noah_code-0.2.3/src/noah_code/custom_commands.py +222 -0
  25. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/event_bridge.py +40 -2
  26. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/events.py +6 -0
  27. noah_code-0.2.3/src/noah_code/github.py +193 -0
  28. noah_code-0.2.3/src/noah_code/hooks.py +136 -0
  29. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/host.py +849 -132
  30. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/llm.py +14 -0
  31. noah_code-0.2.3/src/noah_code/llm_replies.py +96 -0
  32. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/mcp_setup.py +2 -2
  33. noah_code-0.2.3/src/noah_code/nooa_compat.py +69 -0
  34. noah_code-0.2.3/src/noah_code/permissions.py +1003 -0
  35. noah_code-0.2.3/src/noah_code/project_notes.py +115 -0
  36. noah_code-0.2.3/src/noah_code/redaction.py +75 -0
  37. noah_code-0.2.3/src/noah_code/secure_files.py +265 -0
  38. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/sessions.py +113 -10
  39. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/skills_setup.py +2 -1
  40. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/snapshots.py +5 -0
  41. noah_code-0.2.3/src/noah_code/steer.py +73 -0
  42. noah_code-0.2.3/src/noah_code/summarization.py +120 -0
  43. noah_code-0.2.3/src/noah_code/tools/diff_tools.py +263 -0
  44. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/git_tools.py +1 -1
  45. noah_code-0.2.3/src/noah_code/tools/github_tools.py +93 -0
  46. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/lsp_tools.py +13 -9
  47. noah_code-0.2.3/src/noah_code/tools/memory_tools.py +62 -0
  48. noah_code-0.2.3/src/noah_code/tools/plan_tools.py +90 -0
  49. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/process_tools.py +12 -3
  50. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/question_tools.py +5 -1
  51. noah_code-0.2.3/src/noah_code/tools/task_tools.py +219 -0
  52. noah_code-0.2.3/src/noah_code/tools/web_tools.py +384 -0
  53. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/workspace_tools.py +316 -65
  54. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/ui/textual.css +5 -5
  55. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/ui/textual_app.py +523 -72
  56. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/usage.py +35 -0
  57. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/workspace.py +3 -0
  58. noah_code-0.2.3/src/noah_code/worktree.py +242 -0
  59. noah_code-0.2.3/tests/test_agents.py +130 -0
  60. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_approvals.py +1 -1
  61. noah_code-0.2.3/tests/test_budget.py +149 -0
  62. noah_code-0.2.3/tests/test_cache_context.py +262 -0
  63. noah_code-0.2.3/tests/test_checkpoints.py +135 -0
  64. noah_code-0.2.3/tests/test_cli.py +274 -0
  65. noah_code-0.2.3/tests/test_compaction_eviction.py +136 -0
  66. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_config.py +73 -3
  67. noah_code-0.2.3/tests/test_console_ui.py +140 -0
  68. noah_code-0.2.3/tests/test_custom_commands.py +150 -0
  69. noah_code-0.2.3/tests/test_diff_tools.py +108 -0
  70. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_efficiency.py +0 -8
  71. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_event_bridge.py +46 -1
  72. noah_code-0.2.3/tests/test_github.py +182 -0
  73. noah_code-0.2.3/tests/test_hooks.py +200 -0
  74. noah_code-0.2.3/tests/test_host.py +1475 -0
  75. noah_code-0.2.3/tests/test_llm_replies.py +128 -0
  76. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_lsp_tools.py +2 -2
  77. noah_code-0.2.3/tests/test_permissions.py +541 -0
  78. noah_code-0.2.3/tests/test_plan_memory_tools.py +82 -0
  79. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_process_tools.py +19 -4
  80. noah_code-0.2.3/tests/test_project_notes.py +134 -0
  81. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_question_tools.py +1 -1
  82. noah_code-0.2.3/tests/test_redaction.py +60 -0
  83. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_sessions.py +95 -0
  84. noah_code-0.2.3/tests/test_steer.py +72 -0
  85. noah_code-0.2.3/tests/test_task_tools.py +268 -0
  86. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_textual_tui.py +386 -11
  87. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_updates.py +4 -4
  88. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_wave1_e2e.py +8 -3
  89. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_web_tools.py +80 -2
  90. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_workspace_tools.py +249 -3
  91. noah_code-0.2.3/tests/test_worktree.py +92 -0
  92. {noah_code-0.2.2 → noah_code-0.2.3}/uv.lock +208 -2
  93. noah_code-0.2.2/src/noah_code/__init__.py +0 -3
  94. noah_code-0.2.2/src/noah_code/benchmark.py +0 -140
  95. noah_code-0.2.2/src/noah_code/custom_commands.py +0 -103
  96. noah_code-0.2.2/src/noah_code/permissions.py +0 -483
  97. noah_code-0.2.2/src/noah_code/summarization.py +0 -34
  98. noah_code-0.2.2/src/noah_code/tools/task_tools.py +0 -126
  99. noah_code-0.2.2/src/noah_code/tools/web_tools.py +0 -176
  100. noah_code-0.2.2/tests/test_agents.py +0 -52
  101. noah_code-0.2.2/tests/test_cli.py +0 -155
  102. noah_code-0.2.2/tests/test_custom_commands.py +0 -50
  103. noah_code-0.2.2/tests/test_host.py +0 -610
  104. noah_code-0.2.2/tests/test_permissions.py +0 -152
  105. noah_code-0.2.2/tests/test_task_tools.py +0 -77
  106. {noah_code-0.2.2 → noah_code-0.2.3}/.github/workflows/release.yml +0 -0
  107. {noah_code-0.2.2 → noah_code-0.2.3}/docs/assets/noah-in-action.svg +0 -0
  108. {noah_code-0.2.2 → noah_code-0.2.3}/docs/releases/v0.1.0.md +0 -0
  109. {noah_code-0.2.2 → noah_code-0.2.3}/docs/releases/v0.2.1.md +0 -0
  110. {noah_code-0.2.2 → noah_code-0.2.3}/docs/releases/v0.2.2.md +0 -0
  111. {noah_code-0.2.2 → noah_code-0.2.3}/docs/security.md +0 -0
  112. {noah_code-0.2.2 → noah_code-0.2.3}/install.sh +0 -0
  113. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/composer.py +0 -0
  114. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/credentials.py +0 -0
  115. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/macos_sandbox.py +0 -0
  116. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/providers.py +0 -0
  117. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/themes.py +0 -0
  118. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tool_output.py +0 -0
  119. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/__init__.py +0 -0
  120. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/tools/media_tools.py +0 -0
  121. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/ui/__init__.py +0 -0
  122. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/ui/console.py +0 -0
  123. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/ui/protocol.py +0 -0
  124. {noah_code-0.2.2 → noah_code-0.2.3}/src/noah_code/updates.py +0 -0
  125. {noah_code-0.2.2 → noah_code-0.2.3}/tests/conftest.py +0 -0
  126. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_agent_security.py +0 -0
  127. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_composer.py +0 -0
  128. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_credentials.py +0 -0
  129. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_event_bridge_and_shell.py +0 -0
  130. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_git_tools.py +0 -0
  131. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_installer.py +0 -0
  132. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_llm.py +0 -0
  133. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_mcp_setup.py +0 -0
  134. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_providers.py +0 -0
  135. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_run_exit.py +0 -0
  136. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_skills_setup.py +0 -0
  137. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_snapshots.py +0 -0
  138. {noah_code-0.2.2 → noah_code-0.2.3}/tests/test_summarization.py +0 -0
@@ -9,10 +9,15 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
 
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
12
16
  jobs:
13
17
  quality:
14
18
  name: Python ${{ matrix.python-version }} quality
15
19
  runs-on: ubuntu-latest
20
+ timeout-minutes: 30
16
21
  strategy:
17
22
  fail-fast: false
18
23
  matrix:
@@ -46,7 +51,17 @@ jobs:
46
51
  - name: Lint
47
52
  run: uv run ruff check src tests
48
53
 
54
+ - name: Type check
55
+ run: uv run mypy src/noah_code
56
+
57
+ - name: Test with coverage (3.12 only)
58
+ if: matrix.python-version == '3.12'
59
+ run: |
60
+ uv run pytest tests --cov=noah_code --cov-report=term-missing \
61
+ --cov-fail-under=70 -W error::pytest.PytestUnraisableExceptionWarning
62
+
49
63
  - name: Test
64
+ if: matrix.python-version != '3.12'
50
65
  run: uv run pytest tests -W error::pytest.PytestUnraisableExceptionWarning
51
66
 
52
67
  - name: Build distributions
@@ -55,6 +70,7 @@ jobs:
55
70
  platform:
56
71
  name: ${{ matrix.name }} smoke test
57
72
  runs-on: ${{ matrix.runner }}
73
+ timeout-minutes: 40
58
74
  strategy:
59
75
  fail-fast: false
60
76
  matrix:
@@ -11,3 +11,6 @@ build/
11
11
  htmlcov/
12
12
  traces/
13
13
  .DS_Store
14
+ docs/superpowers/plans/
15
+ docs/superpowers/specs/
16
+ .noah-code/
@@ -0,0 +1,8 @@
1
+ # Pre-commit hooks mirroring the CI lint gate.
2
+ # Install with: uv run pre-commit install (or `pre-commit install` once installed)
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.16.1
6
+ hooks:
7
+ - id: ruff-check
8
+ args: [--fix]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: noah-code
3
- Version: 0.2.2
3
+ Version: 0.2.3
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
@@ -28,9 +28,10 @@ Requires-Dist: pydantic>=2.5.0
28
28
  Requires-Dist: pyyaml>=6.0.0
29
29
  Requires-Dist: rich>=13.0.0
30
30
  Requires-Dist: textual>=1.0.0
31
- Requires-Dist: tomli>=2.0.0; python_version < '3.11'
32
31
  Provides-Extra: dev
32
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
33
33
  Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
34
35
  Requires-Dist: pytest>=8.0.0; extra == 'dev'
35
36
  Requires-Dist: ruff>=0.8.0; extra == 'dev'
36
37
  Provides-Extra: mcp
@@ -45,7 +46,7 @@ Description-Content-Type: text/markdown
45
46
 
46
47
  # Noah Code
47
48
 
48
- **A terminal coding harness built on NVIDIA's NOAA framework**
49
+ **A terminal coding agent built on NVIDIA's NOAA framework**
49
50
 
50
51
  [![PyPI](https://img.shields.io/pypi/v/noah-code.svg)](https://pypi.org/project/noah-code/)
51
52
  [![CI](https://github.com/skundu42/noah-code/actions/workflows/ci.yml/badge.svg)](https://github.com/skundu42/noah-code/actions/workflows/ci.yml)
@@ -57,9 +58,9 @@ Description-Content-Type: text/markdown
57
58
 
58
59
  <p align="center"><sub>The real Textual interface, captured from a deterministic Noah Code session.</sub></p>
59
60
 
60
- Noah keeps the conversation central while the context rail tracks the workspace, model, session,
61
- token usage, and current plan. Tool execution stays visible, completed work compacts into readable
62
- records, and every session remains scoped to its repository.
61
+ Noah keeps the conversation central while the context rail tracks live work, Git changes, session,
62
+ model usage, and the current plan. Tool execution stays visible, completed work compacts into
63
+ readable records, and every session remains scoped to its repository.
63
64
 
64
65
  Built on the [NVIDIA OO Agents (NOOA)](https://github.com/NVIDIA-NeMo/labs-OO-Agents) runtime.
65
66
 
@@ -96,6 +97,9 @@ configuration or session history.
96
97
  file edits even after restarting Noah.
97
98
  - **Persistent sessions.** Resume repository-scoped conversations, todos, model choices, and
98
99
  automatically compacted context without losing the full underlying tool results.
100
+ - **Token-efficient by construction.** Lean tool-output bounds with disk-backed recall, condensed
101
+ subagent results, cache-stable request prefixes (volatile status arrives as appended events),
102
+ and pointer-eviction compaction — measured live with `/tokens`.
99
103
  - **Explicit control.** Switch between implementation-focused **build** mode and read-only
100
104
  **plan** mode, with ordered `allow`, `ask`, and `deny` permission rules.
101
105
  - **Extensible workflows.** Add slash commands, opt-in skills, MCP servers, or markdown subagents;
@@ -143,7 +147,6 @@ noah --version
143
147
  noah doctor .
144
148
  noah config show .
145
149
  noah update --check
146
- noah benchmark .
147
150
  ```
148
151
 
149
152
  The package also installs `noah-code` and `nc` as equivalent entry points. Because `nc` commonly
@@ -164,12 +167,13 @@ Type `/` to search the full command and configuration reference. The most common
164
167
  | `/theme` | Choose Atom One Dark, Noah Ocean, Graphite, or High Contrast |
165
168
  | `/diff` | Review staged and unstaged changes |
166
169
  | `/undo` / `/redo` | Traverse the persistent edit journal |
167
- | `/tokens` | Inspect tokens, cache usage, model wait, and tool output |
170
+ | `/tokens` | Inspect tokens, cache usage, prefix stability, model wait, and tool output |
168
171
  | `/efficiency` | Switch between `fast`, `balanced`, and `deep` budgets |
169
172
 
170
- On wide terminals, the side rail keeps the active workspace, session, model, tokens, update state,
171
- and plan in view. The main pane remains centered on the Noah mark until the first prompt, then
172
- becomes the conversation and execution timeline.
173
+ On wide terminals, the side rail prioritizes the active operation, Git branch and change counts,
174
+ session, model usage, update state, and plan. Git status is refreshed in the background at turn
175
+ boundaries, so the animated working state stays responsive. The main pane remains centered on the
176
+ Noah mark until the first prompt, then becomes the conversation and execution timeline.
173
177
 
174
178
  ## Models and providers
175
179
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Noah Code
4
4
 
5
- **A terminal coding harness built on NVIDIA's NOAA framework**
5
+ **A terminal coding agent built on NVIDIA's NOAA framework**
6
6
 
7
7
  [![PyPI](https://img.shields.io/pypi/v/noah-code.svg)](https://pypi.org/project/noah-code/)
8
8
  [![CI](https://github.com/skundu42/noah-code/actions/workflows/ci.yml/badge.svg)](https://github.com/skundu42/noah-code/actions/workflows/ci.yml)
@@ -14,9 +14,9 @@
14
14
 
15
15
  <p align="center"><sub>The real Textual interface, captured from a deterministic Noah Code session.</sub></p>
16
16
 
17
- Noah keeps the conversation central while the context rail tracks the workspace, model, session,
18
- token usage, and current plan. Tool execution stays visible, completed work compacts into readable
19
- records, and every session remains scoped to its repository.
17
+ Noah keeps the conversation central while the context rail tracks live work, Git changes, session,
18
+ model usage, and the current plan. Tool execution stays visible, completed work compacts into
19
+ readable records, and every session remains scoped to its repository.
20
20
 
21
21
  Built on the [NVIDIA OO Agents (NOOA)](https://github.com/NVIDIA-NeMo/labs-OO-Agents) runtime.
22
22
 
@@ -53,6 +53,9 @@ configuration or session history.
53
53
  file edits even after restarting Noah.
54
54
  - **Persistent sessions.** Resume repository-scoped conversations, todos, model choices, and
55
55
  automatically compacted context without losing the full underlying tool results.
56
+ - **Token-efficient by construction.** Lean tool-output bounds with disk-backed recall, condensed
57
+ subagent results, cache-stable request prefixes (volatile status arrives as appended events),
58
+ and pointer-eviction compaction — measured live with `/tokens`.
56
59
  - **Explicit control.** Switch between implementation-focused **build** mode and read-only
57
60
  **plan** mode, with ordered `allow`, `ask`, and `deny` permission rules.
58
61
  - **Extensible workflows.** Add slash commands, opt-in skills, MCP servers, or markdown subagents;
@@ -100,7 +103,6 @@ noah --version
100
103
  noah doctor .
101
104
  noah config show .
102
105
  noah update --check
103
- noah benchmark .
104
106
  ```
105
107
 
106
108
  The package also installs `noah-code` and `nc` as equivalent entry points. Because `nc` commonly
@@ -121,12 +123,13 @@ Type `/` to search the full command and configuration reference. The most common
121
123
  | `/theme` | Choose Atom One Dark, Noah Ocean, Graphite, or High Contrast |
122
124
  | `/diff` | Review staged and unstaged changes |
123
125
  | `/undo` / `/redo` | Traverse the persistent edit journal |
124
- | `/tokens` | Inspect tokens, cache usage, model wait, and tool output |
126
+ | `/tokens` | Inspect tokens, cache usage, prefix stability, model wait, and tool output |
125
127
  | `/efficiency` | Switch between `fast`, `balanced`, and `deep` budgets |
126
128
 
127
- On wide terminals, the side rail keeps the active workspace, session, model, tokens, update state,
128
- and plan in view. The main pane remains centered on the Noah mark until the first prompt, then
129
- becomes the conversation and execution timeline.
129
+ On wide terminals, the side rail prioritizes the active operation, Git branch and change counts,
130
+ session, model usage, update state, and plan. Git status is refreshed in the background at turn
131
+ boundaries, so the animated working state stays responsive. The main pane remains centered on the
132
+ Noah mark until the first prompt, then becomes the conversation and execution timeline.
130
133
 
131
134
  ## Models and providers
132
135
 
@@ -234,9 +234,10 @@ objective, decisions, files, validation, blockers, and next steps.
234
234
  | Mode | Behavior |
235
235
  |------|----------|
236
236
  | `build` | Reads are allowed; edits and shell commands follow permission rules and ask by default |
237
- | `plan` | Reads are allowed; file edits and mutating shell commands are denied |
237
+ | `plan` | Reads are allowed; file edits and mutating shell commands are denied. `self.plan.write` may pin `.noah-code/plan.md` |
238
238
 
239
- Switch modes with `--mode`, `/mode build`, or `/mode plan`. The active mode is stored with the
239
+ Switch modes with `--mode`, `/mode build`, or `/mode plan`. The agent can propose a switch with
240
+ `self.plan.enter()` / `self.plan.exit_to_build()` after writing a plan. The active mode is stored with the
240
241
  session.
241
242
 
242
243
  Permission rules are evaluated in order, and the last matching rule wins. The default policy:
@@ -246,13 +247,23 @@ Permission rules are evaluated in order, and the last matching rule wins. The de
246
247
  databases. `.env.example` remains readable.
247
248
  - Asks before workspace edits, shell commands, web fetches, web searches, and subagents.
248
249
  - Allows the question tool so the agent can pause for a structured choice.
249
- - Denies `git push`, `git clean`, and `git reset --hard`.
250
+ - Denies `git push`, `git clean`, `git reset --hard`, and mutating `gh pr`
251
+ (`create`, `checkout`, `merge`, `close`, `ready`, `review`). Push and PR
252
+ mutations go through `/pr` / `self.github` instead.
253
+ - Allows listing and viewing pull requests; asks before create, push, checkout,
254
+ or comment.
250
255
  - Keeps file tools inside the active workspace and asks before skill or MCP access.
251
256
  - Denies plan-mode mutations regardless of broader allow rules. Plan mode may still run
252
- read-only subagents.
253
-
254
- `--auto` changes ask decisions to allow but never overrides an explicit deny. Compound shell
255
- commands and mutating or unrecognized Git commands cannot be silently auto-approved.
257
+ read-only subagents. Its shell allowlist accepts only literal, unqualified read-only programs;
258
+ test collection and interpreter execution are not treated as read-only because they can load
259
+ repository code.
260
+
261
+ `--auto` changes routine ask decisions to allow but never overrides an explicit deny.
262
+ Elevated-risk commands such as file removal, downloads, and package installation still require
263
+ explicit approval. Compound shell commands and mutating or unrecognized Git commands cannot be
264
+ silently auto-approved. Interpreters, eval/source commands, and indirect execution wrappers, plus
265
+ arguments hidden behind variable, command, ANSI-C, or brace expansion, are denied under `--auto`;
266
+ run without `--auto` when one of these commands needs explicit approval.
256
267
 
257
268
  ## Installation and updates
258
269
 
@@ -7,28 +7,39 @@ Install the development environment and run the local checks:
7
7
  ```bash
8
8
  uv sync --extra dev --extra mcp --extra tracing
9
9
  uv run ruff check src tests
10
+ uv run mypy src/noah_code
10
11
  uv run pytest tests
11
12
  uv build
12
13
  ```
13
14
 
14
- The default test suite is hermetic and does not require network access or provider keys.
15
+ The default test suite is hermetic and does not require network access or provider keys. A single
16
+ opt-in test performs a live HTTP fetch; run it explicitly on a connected machine:
15
17
 
16
- Run the deterministic efficiency fixture without making provider calls:
18
+ ```bash
19
+ uv run pytest tests -m integration
20
+ ```
21
+
22
+ Measure coverage (a 70% total gate runs in CI):
23
+
24
+ ```bash
25
+ uv run pytest tests --cov=noah_code --cov-report=term-missing
26
+ ```
27
+
28
+ Optional git hooks mirror the lint gate:
17
29
 
18
30
  ```bash
19
- uv run noah benchmark .
20
- uv run noah benchmark . --json
31
+ uvx pre-commit install
21
32
  ```
22
33
 
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.
34
+ Use `/tokens` during a real session to inspect provider-reported token use, cache hits, model wait,
35
+ tool output, and estimated cost.
26
36
 
27
37
  ## CI
28
38
 
29
39
  GitHub Actions runs the complete test suite on Python 3.12 and 3.13, plus platform smoke tests on
30
- Linux and macOS for arm64 and x86_64. Every pull request and push to `main` must pass lint, tests,
31
- lockfile validation, and a package build.
40
+ Linux and macOS for arm64 and x86_64. Every pull request and push to `main` must pass lint, static
41
+ type checking (mypy), tests with a 70% coverage floor, lockfile validation, and a package build.
42
+ Concurrent runs for the same reference are cancelled automatically.
32
43
 
33
44
  ## Releases
34
45
 
@@ -6,7 +6,7 @@ Add reusable Markdown prompts in either location:
6
6
 
7
7
  - `~/.config/noah-code/commands/*.md` for user commands.
8
8
  - `.noah-code/commands/*.md` for repository commands. Repository commands override user commands
9
- with the same name.
9
+ with the same non-built-in name. A repository cannot shadow Noah's built-in slash commands.
10
10
 
11
11
  For example, `.noah-code/commands/fix.md`:
12
12
 
@@ -25,8 +25,13 @@ through `$9`. Front matter may also select a mode or model.
25
25
  ## Subagents
26
26
 
27
27
  The parent agent invokes nested NOOA agents with `self.task.run("explore", prompt)` or
28
- `self.task.run("general", prompt)`. Each child gets isolated in-memory session storage and the
29
- same permission broker. Add project or user markdown agents:
28
+ `self.task.run("general", prompt)`, and fans out independent units concurrently with
29
+ `self.task.run_many([("explore", "..."), ("general", "...")])`. Each child gets isolated
30
+ in-memory session storage, its own permission-engine clone (so concurrent children never race
31
+ on mode), and the same approval broker. Results are bounded: oversized transcripts are
32
+ condensed by the lightweight model (fallback: truncation with a recall pointer) before they
33
+ enter the parent's context. Tune with `subagent_result_max_chars` and
34
+ `max_concurrent_subagents` under `[efficiency]`. Add project or user markdown agents:
30
35
 
31
36
  - `~/.config/noah-code/agents/*.md`
32
37
  - `.noah-code/agents/*.md`
@@ -39,7 +44,14 @@ readonly: true
39
44
  Review the assigned change. Cite files. Do not edit.
40
45
  ```
41
46
 
42
- `/agents` lists discovered names. Project files override user files with the same stem.
47
+ `/agents` lists discovered names. Project files override user files with the same stem, except that
48
+ the built-in `explore` and `general` agents are reserved and cannot be replaced by repository
49
+ content.
50
+
51
+ Repository command and agent files are limited to 64 KiB and must be ordinary, singly linked files
52
+ inside their expected `.noah-code` directory. Symlinks, hardlinks, linked directories, special
53
+ files, and oversized files are ignored. User-level files remain linkable because they are trusted
54
+ configuration owned by the user.
43
55
 
44
56
  ## Skills
45
57
 
@@ -4,14 +4,14 @@
4
4
 
5
5
  | Key | Action |
6
6
  |-----|--------|
7
- | `Enter` | Send the current message |
7
+ | `Enter` | Send the current message, or queue a follow-up while a turn is running |
8
8
  | `Shift+Enter` | Insert a newline without sending |
9
9
  | `Tab` | Toggle `build`/`plan` mode; accept the highlighted slash option while suggestions are open |
10
10
  | `Ctrl+P` | Open the command palette |
11
11
  | `Ctrl+K` | Open the searchable skills picker |
12
12
  | `Ctrl+O` | Open the session picker |
13
13
  | `Ctrl+N` | Start a new session |
14
- | `Ctrl+C` | Cancel the active turn; press twice while idle to quit |
14
+ | `Ctrl+C` | Cancel the active turn and clear queued follow-ups; press twice while idle to quit |
15
15
  | `Ctrl+Q` | Quit |
16
16
  | `F1` or `?` | Show help |
17
17
  | `F2` | Open recent activity and full captured output |
@@ -22,10 +22,11 @@ At an approval prompt, press `1` to approve once, `2` to remember the approval f
22
22
  session, or `3`/`Esc` to reject it.
23
23
 
24
24
  The TUI uses Atom One Dark by default and also includes Noah Ocean, Graphite, and High Contrast.
25
- Switch and persist the active palette with `/theme`. Its conversation-first layout adapts to terminal size. At
26
- 110 columns or wider, a context rail shows the session, active tool, and up to six open or blocked
27
- todos. Narrow terminals retain the transcript, live activity, suggestions, and composer without
28
- the rail. Terminals 25 rows high or shorter use compact spacing.
25
+ Switch and persist the active palette with `/theme`. Its conversation-first layout adapts to
26
+ terminal size. At 110 columns or wider, a change-ledger rail prioritizes the current action, Git
27
+ branch and staged/modified/new counts, session, model usage, and up to six open or blocked todos.
28
+ Narrow terminals retain the transcript, live activity, suggestions, and composer without the rail.
29
+ Terminals 25 rows high or shorter use compact spacing.
29
30
 
30
31
  Type `/` in the composer to open the inline command list; the list remains visible and filters
31
32
  continuously. Use `Up`/`Down` to highlight a command, `Enter` or `Tab` to complete it, and `Esc` to
@@ -33,8 +34,29 @@ close the list. Press `Enter` again to run the completed command. Typing `/confi
33
34
  to every resolved configuration path and its current redacted value.
34
35
 
35
36
  Until a session has its first user prompt, the main pane keeps the Noah mark centered. Startup,
36
- workspace, model, mode, and update state live in the context rail on wide terminals. Existing
37
- sessions with user history restore their transcript normally.
37
+ repository changes, model, mode, usage, and update state live in the context rail on wide
38
+ terminals. Git status is collected in a background worker at startup and turn boundaries; spinner
39
+ frames update only the header and working banner. Existing sessions with user history restore
40
+ their transcript normally.
41
+
42
+ ### Mid-turn follow-ups
43
+
44
+ While Noah is working, the composer stays open. `Enter` queues the current text instead of starting
45
+ a second turn. Chrome shows `queued · n`. When the in-flight `handle()` returns (`DONE`,
46
+ `NEED_INPUT`, or `WAIT`), the host injects the next item in the same journaled turn — one persist
47
+ and one checkpoint for the whole steered run. `/undo` therefore reverts every follow-up together.
48
+
49
+ The queue holds at most 5 items. A sixth `Enter` drops the oldest and status-prints
50
+ `steer dropped oldest`. `@path` mentions and `/attach` paths expand when the item is injected, not
51
+ when it is queued. A follow-up that names files Noah cannot resolve is dropped; later items stay.
52
+ `Ctrl+C` cancels the turn and clears the queue. Switching or starting a session also clears it.
53
+
54
+ Approval and `ask.question` modals keep the composer. Queueing resumes after the modal closes.
55
+
56
+ These slash commands still run while a turn is in progress: `/status`, `/tokens`, `/todos`,
57
+ `/help`, `/trace`. `/attach PATH` remembers the file for the next queued follow-up. `/exit` cancels
58
+ the turn (and the queue) then leaves. Mutating commands wait until the turn finishes, including
59
+ `/undo`, `/redo`, `/mode`, `/model`, `/diff`, `/new`, `/sessions`, `/worktree`, `/pr`, `/plan`, `/memory`, and `/compact`.
38
60
 
39
61
  Tool and shell output is batched into a live execution panel instead of forcing one full-screen
40
62
  redraw for every chunk. While a turn is running, a spinner names the current action the way
@@ -57,7 +79,11 @@ latest 100 activity records, bounded by the configured `max_output_chars` per ac
57
79
  | `/reasoning [EFFORT]` | Show or set default/none/minimal/low/medium/high/xhigh for this session |
58
80
  | `/reasoning --global EFFORT` | Set reasoning effort for this and future sessions |
59
81
  | `/providers [use PROVIDER MODEL]` | Search and securely configure API providers |
60
- | `/session`, `/sessions`, `/new`, `/continue` | Inspect, switch, create, and resume sessions |
82
+ | `/session`, `/sessions`, `/new`, `/continue` | Inspect, switch, create, and resume sessions. `/sessions` lists the whole git-repo family (primary checkout plus isolated copies) |
83
+ | `/worktree` | Opt-in isolation: create a linked git worktree and start a new session there. Subcommands: `create [NAME]`, `list`, `remove NAME`. `/new` stays on the current directory. CLI: `noah worktree create` prints a path and does not start a session |
84
+ | `/pr` | First-class GitHub pull-request loop. Subcommands: `list`, `view [N]`, `create [TITLE]`, `push`, `checkout N`, `comment N TEXT`. `/pr 12` views PR 12. Create pushes HEAD through the host (never via bash) then opens the PR. CLI: `noah pr` |
85
+ | `/plan` | Show the pinned `.noah-code/plan.md`. `/plan clear` dismisses it. In plan mode the agent writes this file with `self.plan.write`, then `self.plan.exit_to_build` asks to switch to build and follow it |
86
+ | `/memory` | Show project conventions in `.noah-code/memory.md`. `/memory save FACT`, `/memory forget TEXT`, `/memory clear`. The agent can `self.memory.save`; successful turns may auto-extract tagged conventions |
61
87
  | `/compact` | Apply a coding checkpoint to eligible older context |
62
88
  | `/tokens` | Show tokens, cache hits, cost, model wait, and tool-output volume |
63
89
  | `/efficiency [fast|balanced|deep]` | Show or switch live tool-output budgets |
@@ -95,11 +121,23 @@ after resuming it. Other sessions and repositories keep their existing defaults
95
121
  noah sessions list .
96
122
  noah sessions show SESSION_ID
97
123
  noah sessions delete SESSION_ID
124
+ noah worktree create [NAME]
125
+ noah worktree list
126
+ noah worktree remove NAME
127
+ noah pr list
128
+ noah pr view [N]
129
+ noah pr create [TITLE]
130
+ noah pr push
131
+ noah pr checkout N
132
+ noah pr comment N TEXT
98
133
  ```
99
134
 
100
135
  Each session has a NOOA-backed SQLite database plus metadata for its workspace identity, model,
101
136
  mode, title, remembered permission rules, todos, and edit journal. Session files are created with
102
- private filesystem permissions and cannot accidentally be resumed against another workspace.
137
+ private filesystem permissions. `/sessions` lists every session in the same git repository family
138
+ (primary checkout plus Noah worktree copies). Switching or `noah --session` / `--continue` rebinds
139
+ the workspace to that session's stored path. A missing copy errors with `worktree missing` instead
140
+ of falling back to the current directory. Deleting a session does not remove its worktree.
103
141
 
104
142
  The latest 50 persisted user, agent, summary, error, and activity events are restored after the
105
143
  TUI's first paint. `F3` loads older history in read-only pages of 50, so resuming a long session
@@ -146,9 +184,13 @@ Lifecycle updates appear in the TUI without copying continuous logs into model c
146
184
  The parent agent can run isolated NOOA subagents with `self.task.run("explore", ...)` or
147
185
  `self.task.run("general", ...)`. Explore is read-only. General can edit but does not own todos.
148
186
  Custom agents are markdown files in `.noah-code/agents/` or `~/.config/noah-code/agents/`. List
149
- them with `/agents`. Plan mode can run read-only agents only.
187
+ them with `/agents`. Repository files cannot replace the built-in `explore` or `general` agents,
188
+ and unsafe linked or oversized repository definitions are ignored. Plan mode can run read-only
189
+ agents only.
150
190
 
151
- `self.web.fetch(url)` and `self.web.search(query)` ask before leaving the machine.
191
+ `self.web.fetch(url)` and `self.web.search(query)` ask before leaving the machine. Fetch follows a
192
+ bounded number of redirects and accepts only public HTTP(S) destinations; private, loopback,
193
+ link-local, and mixed public/private DNS results are rejected at every hop.
152
194
  `self.ask.question(header, prompt, options)` pauses the turn for a structured choice.
153
195
 
154
196
  Type `@path` in the composer to inline a workspace file or attach a PNG/JPEG/WebP/GIF as a NOOA
@@ -16,7 +16,7 @@ repositories.
16
16
  - Added paginated, read-only conversation history through `F3` when resuming sessions.
17
17
  - Added keyboard-driven command and session pickers, safer approval cards, scroll locking, and new
18
18
  output indicators.
19
- - Batched high-volume shell events and bounded display history; the 2,000-chunk local benchmark
19
+ - Batched high-volume shell events and bounded display history; a 2,000-chunk stress measurement
20
20
  improved from approximately 454 ms to 123 ms.
21
21
 
22
22
  ## Reliability
@@ -1,6 +1,6 @@
1
1
  # Noah Code v0.2.0
2
2
 
3
- This release turns Noah Code into a more capable, responsive coding harness while keeping its
3
+ This release turns Noah Code into a more capable, responsive coding agent while keeping its
4
4
  NOOA-based execution path compact and token efficient.
5
5
 
6
6
  ## Highlights
@@ -26,8 +26,8 @@ NOOA-based execution path compact and token efficient.
26
26
  - Added `fast`, `balanced`, and `deep` efficiency profiles, compact NOOA trajectory rendering,
27
27
  bounded reopenable tool previews, batched repository inspection, and cache-friendly context
28
28
  refreshes.
29
- - Added `/tokens` reporting and an offline benchmark for inspecting prompt-cache, model-wait,
30
- tool-output, and estimated token usage.
29
+ - Added `/tokens` reporting for inspecting prompt-cache, model-wait, tool-output, and estimated
30
+ token usage.
31
31
  - Upgraded the runtime integration to NOOA 0.0.9.
32
32
 
33
33
  ## Reliability
@@ -0,0 +1,50 @@
1
+ # Noah Code v0.2.3
2
+
3
+ This release focuses Noah Code on the core coding-agent product while making long-running work
4
+ safer, more recoverable, and easier to follow from the terminal.
5
+
6
+ ## Agent workflow
7
+
8
+ - Added mid-turn steering so follow-up instructions can be queued without interrupting active work.
9
+ - Added durable plan handoff and project memory, including explicit plan-mode boundaries and a
10
+ guided transition back to build mode.
11
+ - Added isolated Git worktrees, repository-family sessions, and a first-class GitHub pull-request
12
+ workflow for listing, reviewing, creating, pushing, checking out, and commenting on PRs.
13
+ - Added session budgets, turn-boundary Git checkpoints, configurable hooks, and persistent undo/redo
14
+ safeguards for more controlled autonomous work.
15
+ - Improved conversational handling, context compaction, tool-result retention, and subagent result
16
+ shaping to keep long sessions useful and token efficient.
17
+
18
+ ## Interface
19
+
20
+ - Redesigned the wide-terminal context rail around the current action, Git branch and staged,
21
+ modified, and untracked counts, session and model state, usage and cost, and the active plan.
22
+ - Moved Git status collection to a background worker and stopped spinner frames from rebuilding the
23
+ rail or rereading plan state, keeping the TUI responsive during active turns.
24
+ - Added contextual busy/idle key hints, clearer live activity, paginated history, searchable
25
+ commands and sessions, and a detailed change ledger with validation and checkpoint controls.
26
+
27
+ ## Security and reliability
28
+
29
+ - Enforced read-only plan-mode boundaries across tools, shell execution, task delegation, and
30
+ project-note writes.
31
+ - Hardened permission parsing, credential and error redaction, generated-code isolation, secure file
32
+ handling, and session persistence against races and concurrent edits.
33
+ - Made web access DNS-pinned, redirect-safe, and public-unicast-only to prevent private-network and
34
+ mixed-resolution request forgery.
35
+ - Removed the SWE-bench runner, offline benchmark command, automation-only `exec` driver, and LLM
36
+ response record/replay cache so the package is solely the core product.
37
+ - Expanded the hermetic suite to 470 passing tests across the runtime, interface, security, and
38
+ repository workflows.
39
+
40
+ ## Upgrade
41
+
42
+ Existing managed installations can run:
43
+
44
+ ```bash
45
+ noah update
46
+ ```
47
+
48
+ New installations can use the one-command installer from the README.
49
+
50
+ **Full changelog:** https://github.com/skundu42/noah-code/compare/v0.2.2...v0.2.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "noah-code"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  description = "Noah Code terminal coding agent, built on NVIDIA OO Agents (NOOA)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12,<3.14"
@@ -28,7 +28,6 @@ dependencies = [
28
28
  "pydantic>=2.5.0",
29
29
  "PyYAML>=6.0.0",
30
30
  "packaging>=24.0",
31
- "tomli>=2.0.0; python_version < '3.11'",
32
31
  "rich>=13.0.0",
33
32
  "textual>=1.0.0",
34
33
  ]
@@ -44,7 +43,9 @@ Releases = "https://github.com/skundu42/noah-code/releases"
44
43
  dev = [
45
44
  "pytest>=8.0.0",
46
45
  "pytest-asyncio>=0.24.0",
46
+ "pytest-cov>=5.0.0",
47
47
  "ruff>=0.8.0",
48
+ "mypy>=1.13.0",
48
49
  ]
49
50
  tui = [
50
51
  "textual>=1.0.0",
@@ -77,6 +78,8 @@ package = true
77
78
  asyncio_mode = "auto"
78
79
  asyncio_default_fixture_loop_scope = "function"
79
80
  testpaths = ["tests"]
81
+ # Keep the default suite hermetic; opt in with `pytest -m integration`.
82
+ addopts = ["-m", "not integration"]
80
83
  markers = [
81
84
  "integration: tests that may touch the network (deselect by default)",
82
85
  ]
@@ -89,3 +92,27 @@ src = ["src", "tests"]
89
92
  [tool.ruff.lint]
90
93
  select = ["E", "F", "I", "UP", "B", "SIM"]
91
94
  ignore = ["E501"]
95
+
96
+ [tool.mypy]
97
+ python_version = "3.12"
98
+ files = ["src/noah_code"]
99
+ check_untyped_defs = true
100
+ no_implicit_optional = true
101
+ warn_redundant_casts = true
102
+ warn_unused_ignores = true
103
+ # NOOA's tool/skill framework stacks @hidden/@property and spec() decorators
104
+ # in ways mypy's plugin model does not describe; these codes are noise here.
105
+ disable_error_code = ["prop-decorator", "empty-body"]
106
+
107
+ [[tool.mypy.overrides]]
108
+ # nooa resolves attributes lazily (PEP 562) and litellm ships no stubs;
109
+ # treat every public surface as Any instead of half-analyzing sources.
110
+ module = ["nooa", "nooa.*", "nooa_cli", "nooa_cli.*", "litellm", "litellm.*"]
111
+ follow_imports = "skip"
112
+ ignore_missing_imports = true
113
+
114
+ [dependency-groups]
115
+ dev = [
116
+ "mypy>=2.3.1",
117
+ "types-pyyaml>=6.0.12.20260815",
118
+ ]
@@ -0,0 +1,3 @@
1
+ """Noah Code: terminal coding agent on NVIDIA OO Agents."""
2
+
3
+ __version__ = "0.2.3"
@@ -3,4 +3,4 @@
3
3
  from noah_code.cli import main
4
4
 
5
5
  if __name__ == "__main__":
6
- raise SystemExit(main())
6
+ main()