ness-agent 0.2.2__tar.gz → 0.2.4__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 (337) hide show
  1. {ness_agent-0.2.2 → ness_agent-0.2.4}/.gitignore +5 -1
  2. {ness_agent-0.2.2 → ness_agent-0.2.4}/CHANGELOG.md +42 -4
  3. {ness_agent-0.2.2 → ness_agent-0.2.4}/CONTRIBUTING.md +2 -1
  4. {ness_agent-0.2.2 → ness_agent-0.2.4}/PKG-INFO +11 -6
  5. {ness_agent-0.2.2 → ness_agent-0.2.4}/README.md +10 -5
  6. ness_agent-0.2.4/assets/ness-agent-img_page_1.jpg +0 -0
  7. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/architecture.md +23 -2
  8. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/cli.md +7 -7
  9. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/configuration.md +14 -11
  10. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/sdk-api.md +30 -5
  11. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/sdk.md +42 -0
  12. ness_agent-0.2.4/evals/README.md +68 -0
  13. ness_agent-0.2.4/evals/TB_BENCH.md +67 -0
  14. ness_agent-0.2.4/evals/codex/codex_chat_model.py +367 -0
  15. ness_agent-0.2.4/evals/codex/ness_harbor_agent.py +533 -0
  16. ness_agent-0.2.4/evals/codex/ness_session.py +133 -0
  17. ness_agent-0.2.4/evals/configs/tb-errored-3-codex.yaml +18 -0
  18. ness_agent-0.2.4/evals/configs/tb-multimedia-5-codex.yaml +20 -0
  19. ness_agent-0.2.4/evals/configs/tb-single-task-codex.yaml +16 -0
  20. ness_agent-0.2.4/evals/configs/tb-single-task.yaml +16 -0
  21. ness_agent-0.2.4/evals/configs/tb-targeted-3-codex.yaml +18 -0
  22. ness_agent-0.2.4/evals/configs/tb-text-only-20-codex.yaml +35 -0
  23. ness_agent-0.2.4/evals/configs/tb-text-only-20.yaml +35 -0
  24. ness_agent-0.2.4/evals/ness_harbor_agent.py +416 -0
  25. ness_agent-0.2.4/evals/ness_session.py +129 -0
  26. ness_agent-0.2.4/evals/scripts/tb_bench.py +201 -0
  27. {ness_agent-0.2.2 → ness_agent-0.2.4}/pyproject.toml +13 -1
  28. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/agent.py +45 -3
  29. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/context/budget.py +26 -3
  30. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/graph/helpers.py +132 -1
  31. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/graph/nodes.py +98 -32
  32. ness_agent-0.2.4/src/ness_agent/instructions/compaction.py +18 -0
  33. ness_agent-0.2.4/src/ness_agent/media.py +74 -0
  34. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/permissions.py +72 -28
  35. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/session.py +32 -3
  36. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/session_context.py +1 -0
  37. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/__init__.py +40 -12
  38. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/fs.py +77 -10
  39. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/cost.py +83 -14
  40. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/messages.py +3 -1
  41. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/types.py +2 -1
  42. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/chat_model.py +2 -2
  43. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/coding_session.py +99 -43
  44. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/config.py +27 -19
  45. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/config_store.py +3 -1
  46. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/events.py +11 -8
  47. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/headless.py +1 -0
  48. ness_agent-0.2.4/src/ness_cli/instructions/compaction.md +18 -0
  49. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/adapter.py +12 -5
  50. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/auth.py +2 -2
  51. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/chat_model.py +38 -10
  52. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/transport.py +136 -2
  53. ness_agent-0.2.4/src/ness_cli/provider/opencode/__init__.py +1 -0
  54. ness_agent-0.2.4/src/ness_cli/provider/opencode/adapter.py +281 -0
  55. ness_agent-0.2.4/src/ness_cli/provider/opencode/catalog.py +101 -0
  56. ness_agent-0.2.4/src/ness_cli/provider/opencode/chat_model.py +24 -0
  57. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/openrouter/chat_model.py +53 -14
  58. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/registry.py +2 -0
  59. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/app.py +2 -3
  60. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/chrome.py +6 -4
  61. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/commands.py +15 -11
  62. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/config_flow.py +3 -4
  63. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/config_registry.py +21 -9
  64. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/images.py +4 -28
  65. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/main.py +1 -0
  66. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/pickers.py +3 -4
  67. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/transcript.py +5 -2
  68. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/turn_renderer.py +7 -1
  69. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/sdk_example_usage.md +9 -6
  70. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_anthropic_messages.py +69 -0
  71. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/conftest.py +19 -1
  72. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_chrome.py +5 -5
  73. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_codex_provider.py +167 -2
  74. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_coding_session.py +34 -1
  75. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_commands.py +9 -7
  76. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_config_flow.py +10 -2
  77. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_config_store.py +13 -0
  78. ness_agent-0.2.4/tests/test_cli/test_opencode_provider.py +216 -0
  79. ness_agent-0.2.4/tests/test_codex_harbor_agent.py +118 -0
  80. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_fs.py +76 -2
  81. ness_agent-0.2.4/tests/test_media.py +87 -0
  82. ness_agent-0.2.4/tests/test_media_tool_flow.py +214 -0
  83. ness_agent-0.2.4/tests/test_opencode_live.py +30 -0
  84. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_sdk_regressions.py +434 -3
  85. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/tracing/test_cost.py +18 -2
  86. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/tracing/test_integration.py +4 -1
  87. {ness_agent-0.2.2 → ness_agent-0.2.4}/uv.lock +1301 -10
  88. ness_agent-0.2.2/.agents/skills/brandkit/SKILL.md +0 -798
  89. ness_agent-0.2.2/.agents/skills/design-taste-frontend/SKILL.md +0 -1206
  90. ness_agent-0.2.2/.agents/skills/gpt-taste/SKILL.md +0 -74
  91. ness_agent-0.2.2/.agents/skills/high-end-visual-design/SKILL.md +0 -98
  92. ness_agent-0.2.2/.agents/skills/image-to-code/SKILL.md +0 -1228
  93. ness_agent-0.2.2/.agents/skills/imagegen-frontend-web/SKILL.md +0 -987
  94. ness_agent-0.2.2/.agents/skills/industrial-brutalist-ui/SKILL.md +0 -92
  95. ness_agent-0.2.2/.agents/skills/minimalist-ui/SKILL.md +0 -85
  96. ness_agent-0.2.2/.agents/skills/redesign-existing-projects/SKILL.md +0 -178
  97. ness_agent-0.2.2/.agents/skills/stitch-design-taste/DESIGN.md +0 -121
  98. ness_agent-0.2.2/.agents/skills/stitch-design-taste/SKILL.md +0 -184
  99. ness_agent-0.2.2/.ness/NESS.md +0 -1
  100. ness_agent-0.2.2/.ness/agents/explore.md +0 -10
  101. ness_agent-0.2.2/.ness/hooks.json +0 -9
  102. ness_agent-0.2.2/.ness/mcp.json +0 -13
  103. ness_agent-0.2.2/.ness/permissions.json +0 -36
  104. ness_agent-0.2.2/.ness/skills/brandkit/SKILL.md +0 -798
  105. ness_agent-0.2.2/.ness/skills/design-taste-frontend/SKILL.md +0 -1206
  106. ness_agent-0.2.2/.ness/skills/gpt-taste/SKILL.md +0 -74
  107. ness_agent-0.2.2/.ness/skills/high-end-visual-design/SKILL.md +0 -98
  108. ness_agent-0.2.2/.ness/skills/image-to-code/SKILL.md +0 -1228
  109. ness_agent-0.2.2/.ness/skills/imagegen-frontend-web/SKILL.md +0 -987
  110. ness_agent-0.2.2/.ness/skills/industrial-brutalist-ui/SKILL.md +0 -92
  111. ness_agent-0.2.2/.ness/skills/minimalist-ui/SKILL.md +0 -85
  112. ness_agent-0.2.2/.ness/skills/redesign-existing-projects/SKILL.md +0 -178
  113. ness_agent-0.2.2/.ness/skills/stitch-design-taste/DESIGN.md +0 -121
  114. ness_agent-0.2.2/.ness/skills/stitch-design-taste/SKILL.md +0 -184
  115. ness_agent-0.2.2/src/ness_agent/instructions/compaction.py +0 -14
  116. ness_agent-0.2.2/src/ness_cli/instructions/compaction.md +0 -14
  117. ness_agent-0.2.2/website/.gitignore +0 -24
  118. ness_agent-0.2.2/website/.oxlintrc.json +0 -8
  119. ness_agent-0.2.2/website/AGENTS.md +0 -54
  120. ness_agent-0.2.2/website/README.md +0 -32
  121. ness_agent-0.2.2/website/assets/viewport.png +0 -0
  122. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/.gitkeep +0 -0
  123. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow1.png +0 -0
  124. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow2.png +0 -0
  125. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow3.png +0 -0
  126. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow4.png +0 -0
  127. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow5.png +0 -0
  128. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow6.png +0 -0
  129. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/assets/flow7.png +0 -0
  130. ness_agent-0.2.2/website/content/blog/inside-coding-agent-building-the-harness-around-the-model/index.md +0 -736
  131. ness_agent-0.2.2/website/index.html +0 -13
  132. ness_agent-0.2.2/website/package-lock.json +0 -3848
  133. ness_agent-0.2.2/website/package.json +0 -39
  134. ness_agent-0.2.2/website/public/.ness/threads/threads.db +0 -0
  135. ness_agent-0.2.2/website/public/favicon.svg +0 -46
  136. ness_agent-0.2.2/website/public/icons.svg +0 -24
  137. ness_agent-0.2.2/website/public/install.ps1 +0 -241
  138. ness_agent-0.2.2/website/public/install.sh +0 -201
  139. ness_agent-0.2.2/website/src/App.css +0 -184
  140. ness_agent-0.2.2/website/src/App.tsx +0 -27
  141. ness_agent-0.2.2/website/src/assets/hero.png +0 -0
  142. ness_agent-0.2.2/website/src/assets/react.svg +0 -1
  143. ness_agent-0.2.2/website/src/assets/vite.svg +0 -1
  144. ness_agent-0.2.2/website/src/content/blog.ts +0 -86
  145. ness_agent-0.2.2/website/src/content/docsRoutes.ts +0 -10
  146. ness_agent-0.2.2/website/src/content/markdown.ts +0 -32
  147. ness_agent-0.2.2/website/src/index.css +0 -2641
  148. ness_agent-0.2.2/website/src/main.tsx +0 -18
  149. ness_agent-0.2.2/website/src/pages/BlogPage.tsx +0 -178
  150. ness_agent-0.2.2/website/src/pages/DocsPage.tsx +0 -259
  151. ness_agent-0.2.2/website/src/pages/HomePage.tsx +0 -80
  152. ness_agent-0.2.2/website/src/pages/NewsPage.tsx +0 -281
  153. ness_agent-0.2.2/website/src/pages/shared/InstallCommand.tsx +0 -84
  154. ness_agent-0.2.2/website/src/pages/shared/MarkdownDocument.tsx +0 -88
  155. ness_agent-0.2.2/website/src/pages/shared/SiteFooter.tsx +0 -36
  156. ness_agent-0.2.2/website/src/pages/shared/SiteShell.tsx +0 -19
  157. ness_agent-0.2.2/website/src/tui/NessLogo.tsx +0 -173
  158. ness_agent-0.2.2/website/src/tui/TuiShell.tsx +0 -711
  159. ness_agent-0.2.2/website/src/tui/VariantNavbar.tsx +0 -47
  160. ness_agent-0.2.2/website/src/tui/steps.ts +0 -200
  161. ness_agent-0.2.2/website/src/tui/types.ts +0 -39
  162. ness_agent-0.2.2/website/src/tui/useTheme.ts +0 -30
  163. ness_agent-0.2.2/website/tsconfig.app.json +0 -29
  164. ness_agent-0.2.2/website/tsconfig.json +0 -7
  165. ness_agent-0.2.2/website/tsconfig.node.json +0 -23
  166. ness_agent-0.2.2/website/vite.config.ts +0 -23
  167. {ness_agent-0.2.2 → ness_agent-0.2.4}/.env.example +0 -0
  168. {ness_agent-0.2.2 → ness_agent-0.2.4}/.github/workflows/ci.yml +0 -0
  169. {ness_agent-0.2.2 → ness_agent-0.2.4}/.github/workflows/pages.yml +0 -0
  170. {ness_agent-0.2.2 → ness_agent-0.2.4}/.github/workflows/publish.yml +0 -0
  171. {ness_agent-0.2.2 → ness_agent-0.2.4}/.python-version +0 -0
  172. {ness_agent-0.2.2 → ness_agent-0.2.4}/AGENTS.md +0 -0
  173. {ness_agent-0.2.2 → ness_agent-0.2.4}/LICENSE +0 -0
  174. {ness_agent-0.2.2 → ness_agent-0.2.4}/SECURITY.md +0 -0
  175. {ness_agent-0.2.2 → ness_agent-0.2.4}/assets/banner-dark-geo.svg +0 -0
  176. {ness_agent-0.2.2 → ness_agent-0.2.4}/assets/banner-light-blue-geo.svg +0 -0
  177. {ness_agent-0.2.2 → ness_agent-0.2.4}/assets/banner-light-geo-x.svg +0 -0
  178. {ness_agent-0.2.2 → ness_agent-0.2.4}/assets/banner-light-geo.svg +0 -0
  179. {ness_agent-0.2.2 → ness_agent-0.2.4}/assets/ness_agent_sc.png +0 -0
  180. {ness_agent-0.2.2 → ness_agent-0.2.4}/docs/README.md +0 -0
  181. {ness_agent-0.2.2 → ness_agent-0.2.4}/scripts/fetch_openrouter_models.py +0 -0
  182. {ness_agent-0.2.2 → ness_agent-0.2.4}/skills-lock.json +0 -0
  183. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/__init__.py +0 -0
  184. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/compaction.py +0 -0
  185. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/context/__init__.py +0 -0
  186. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/context/coding_overlay.py +0 -0
  187. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/context/layers.py +0 -0
  188. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/context/overlay.py +0 -0
  189. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/defaults/__init__.py +0 -0
  190. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/defaults/agents/explore.md +0 -0
  191. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/graph/__init__.py +0 -0
  192. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/graph/builder.py +0 -0
  193. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/graph/state.py +0 -0
  194. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/hooks.py +0 -0
  195. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/__init__.py +0 -0
  196. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/act_mode.py +0 -0
  197. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/init_memory.py +0 -0
  198. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/l0_harness.py +0 -0
  199. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/l1_profile.py +0 -0
  200. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/plan_mode.py +0 -0
  201. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/reflection.py +0 -0
  202. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/subagent.py +0 -0
  203. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/instructions/thread_summary.py +0 -0
  204. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/mcp.py +0 -0
  205. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/memory.py +0 -0
  206. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/options.py +0 -0
  207. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/persistence.py +0 -0
  208. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/reflection.py +0 -0
  209. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/skills.py +0 -0
  210. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/ask.py +0 -0
  211. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/discover.py +0 -0
  212. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/search.py +0 -0
  213. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/shell.py +0 -0
  214. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/skill.py +0 -0
  215. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/subagents.py +0 -0
  216. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/todo.py +0 -0
  217. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tools/web.py +0 -0
  218. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/__init__.py +0 -0
  219. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/config.py +0 -0
  220. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/exporters/__init__.py +0 -0
  221. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/exporters/console.py +0 -0
  222. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/exporters/otlp.py +0 -0
  223. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/semconv.py +0 -0
  224. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/tracing/tracer.py +0 -0
  225. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/utils.py +0 -0
  226. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/workspace/__init__.py +0 -0
  227. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/workspace/bootstrap.py +0 -0
  228. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/workspace/git_context.py +0 -0
  229. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_agent/workspace/project_context.py +0 -0
  230. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/__init__.py +0 -0
  231. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/export.py +0 -0
  232. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/factory.py +0 -0
  233. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/goal.py +0 -0
  234. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/__init__.py +0 -0
  235. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/act_mode.md +0 -0
  236. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/goal_generic_repair.md +0 -0
  237. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/goal_judge.md +0 -0
  238. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/goal_repair.md +0 -0
  239. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/init_memory.md +0 -0
  240. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/l0_harness.md +0 -0
  241. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/persona.md +0 -0
  242. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/plan_mode.md +0 -0
  243. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/reflection.md +0 -0
  244. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/subagent.md +0 -0
  245. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/instructions/thread_summary.md +0 -0
  246. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mcp_cli.py +0 -0
  247. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mcp_import.py +0 -0
  248. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mcp_manager.py +0 -0
  249. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mcp_oauth.py +0 -0
  250. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mcp_trust.py +0 -0
  251. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/mentions.py +0 -0
  252. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/paths.py +0 -0
  253. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/prompts.py +0 -0
  254. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/__init__.py +0 -0
  255. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/base.py +0 -0
  256. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/__init__.py +0 -0
  257. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/app_server.py +0 -0
  258. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/browser.py +0 -0
  259. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/codex/catalog.py +0 -0
  260. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/openrouter/__init__.py +0 -0
  261. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/openrouter/adapter.py +0 -0
  262. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/openrouter/catalog.py +0 -0
  263. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/provider/profile.py +0 -0
  264. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/rollback.py +0 -0
  265. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/terminal.py +0 -0
  266. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/__init__.py +0 -0
  267. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/command_catalog.py +0 -0
  268. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/constants.py +0 -0
  269. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/formatting.py +0 -0
  270. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/header.py +0 -0
  271. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/keys.py +0 -0
  272. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/markdown.py +0 -0
  273. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/mentions.py +0 -0
  274. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/models.py +0 -0
  275. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/prompts.py +0 -0
  276. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/render.py +0 -0
  277. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/stream.py +0 -0
  278. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/theme.py +0 -0
  279. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/tool_display.py +0 -0
  280. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/utils.py +0 -0
  281. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/tui/widgets.py +0 -0
  282. {ness_agent-0.2.2 → ness_agent-0.2.4}/src/ness_cli/worktree.py +0 -0
  283. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/mcp_echo_server.py +0 -0
  284. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/sdk_fixtures.py +0 -0
  285. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_ask.py +0 -0
  286. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/__init__.py +0 -0
  287. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_approval_cancel.py +0 -0
  288. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_approval_prompt.py +0 -0
  289. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_cancel.py +0 -0
  290. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_codex_browser.py +0 -0
  291. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_export.py +0 -0
  292. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_header.py +0 -0
  293. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_instructions.py +0 -0
  294. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_markdown_render.py +0 -0
  295. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_mcp_cli.py +0 -0
  296. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_mcp_import.py +0 -0
  297. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_mcp_oauth.py +0 -0
  298. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_mcp_trust.py +0 -0
  299. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_paste_state.py +0 -0
  300. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_picker_layout.py +0 -0
  301. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_print_mode.py +0 -0
  302. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_question_cancel.py +0 -0
  303. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_queue.py +0 -0
  304. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_tool_display.py +0 -0
  305. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_transcript_blocks.py +0 -0
  306. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_transcript_fitcheck.py +0 -0
  307. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_tui_subagent_todos.py +0 -0
  308. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_tui_wiring.py +0 -0
  309. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_turn_renderer.py +0 -0
  310. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_cli/test_version.py +0 -0
  311. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_git_context.py +0 -0
  312. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_goal.py +0 -0
  313. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_grep.py +0 -0
  314. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_mcp.py +0 -0
  315. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_mcp_runtime.py +0 -0
  316. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_memory.py +0 -0
  317. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_model.py +0 -0
  318. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_model_catalog.py +0 -0
  319. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_openrouter_live.py +0 -0
  320. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_options.py +0 -0
  321. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_packaging_smoke.py +0 -0
  322. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_paths.py +0 -0
  323. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_permissions.py +0 -0
  324. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_rollback.py +0 -0
  325. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_sdk_discover.py +0 -0
  326. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_sdk_parity.py +0 -0
  327. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_sdk_skill_view.py +0 -0
  328. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_sdk_smoke.py +0 -0
  329. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_session.py +0 -0
  330. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_shell.py +0 -0
  331. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_subagents.py +0 -0
  332. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_support_layer_wiring.py +0 -0
  333. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_thread_fork.py +0 -0
  334. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_todo.py +0 -0
  335. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/test_web.py +0 -0
  336. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/tracing/__init__.py +0 -0
  337. {ness_agent-0.2.2 → ness_agent-0.2.4}/tests/tracing/test_tracer.py +0 -0
@@ -13,6 +13,7 @@ wheels/
13
13
  # Virtual environments
14
14
  .venv
15
15
  .env
16
+ .env.evals
16
17
 
17
18
  # Ness Agent runtime data
18
19
  .ness/worktrees/
@@ -20,4 +21,7 @@ wheels/
20
21
  .ness/runtime/
21
22
 
22
23
  # SDK Tests
23
- sdk_perf/
24
+ sdk_perf/
25
+
26
+ # Harbor eval outputs
27
+ evals/jobs/
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.4] - 2026-09-08 — Released
11
+
12
+ ### Added
13
+
14
+ - Image-aware `read()` for vision models: PNG, JPEG, WebP, GIF, PPM, BMP, and TIFF files are normalized (EXIF orientation, 2000px long edge, PNG re-encode, 5 MB ceiling) and returned as structured text plus image blocks. Codex and OpenRouter project those tool results into the next model request; text-only sessions get a visible omission instead of a data URL. Base64 stays out of hooks, SQLite events, traces, TUI `tool_end` payloads, and token estimates. PDFs and videos remain unsupported, with a hint to render or extract frames and `read()` the resulting images.
15
+ - Harbor eval adapters for Terminal-Bench 2.1: OpenRouter (`evals.ness_harbor_agent:NessAgent`) and ChatGPT-authenticated Codex (`evals/codex`), plus configs and a `tb_bench.py` runner for the v0.2.3 text-only Codex baseline.
16
+
17
+ ### Changed
18
+
19
+ - Compaction can now summarize inside a long active turn. When the current continuation exceeds a retained-suffix budget (about 40% of usable context, clamped between 8k and 65k tokens), older in-turn work is summarized while a coherent recent suffix is kept verbatim, without splitting a tool-call batch from its results. Later tool loops treat the compacted-history boundary as the start of that continuation.
20
+
21
+ ### Fixed
22
+
23
+ - Oversized active continuations now fail explicitly when no safe retained suffix can fit, instead of reaching the provider with an over-budget request. Compaction-call usage is isolated from parent-call context accounting, and image blocks receive a bounded token allowance without persisting their base64 payloads.
24
+
25
+ ## [0.2.3] - 2026-08-23 — Released
26
+
27
+ ### Added
28
+
29
+ - OpenCode Go as a built-in CLI model provider, with per-model Responses, Chat Completions, and Anthropic Messages routing, live model discovery, separate API-key storage, and rolling 5-hour/weekly/monthly subscription usage in `/status`.
30
+ - Per-session effective SDK configuration: `NessAgent.session()` now accepts main and reflection model overrides, `Session.config` / `Session.cost_tracker` expose the effective session view, and `Session.configure_models()` can rebind one live session without changing its siblings.
31
+ - `NessAgent.configure_default_models()` for updating the model defaults inherited by sessions created in the future.
32
+
33
+ ### Changed
34
+
35
+ - A `NessAgent` now acts as a project-scoped owner of shared services and defaults while every `Session` receives isolated mutable runtime views for options, temporary permission rules, active MCP tools, and cost totals. Thread persistence, hooks, memory, tool definitions, persistent permission rules, tracing, and pricing remain shared.
36
+ - CLI model/provider/reasoning changes now update the selected thread and future sessions only; other live thread runtimes retain the model configuration with which they were created.
37
+ - Cost reporting is session-first: live usage accumulates in both the session tracker and the agent's current-process aggregate, while replayed durable usage restores only the session total.
38
+
39
+ ### Fixed
40
+
41
+ - Concurrent `/new` and `/threads` runtimes no longer overwrite one another's effective models, temporary approvals, MCP activation, per-session callbacks, cost totals, or displayed model/provider metadata.
42
+ - Persistent permission updates are serialized and written atomically while `session` approval rules remain local to the session that created them.
43
+ - Resume restores historical thread cost without double-counting it as new agent spend, forks exclude inherited usage from child totals, and rollback preserves already-incurred session cost.
44
+ - The experimental ChatGPT-authenticated Codex transport now uses one stable UUID per thread for `prompt_cache_key` and the Codex Responses transport's session-routing header without sending public-API-only cache controls; cache reads and writes are reported per call, append-only prefixes can be verified through privacy-safe debug fingerprints, and backend validation errors include their response detail and request ID.
45
+
10
46
  ## [0.2.2] - 2026-08-15 — Released
11
47
 
12
48
  ### Added
@@ -20,7 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
56
 
21
57
  - The SDK `read` tool can now read absolute file paths outside the configured project root; relative paths still resolve from the project root, while write, edit, and delete paths remain project-bound.
22
58
  - The TUI footer now labels Codex plan-backed usage as `subscription` instead of displaying the misleading `$0.0000`, while retaining dollar totals for usage-based providers.
23
- - Codex subscription requests now retry transient SSE failures such as `server_is_overloaded`, service-unavailable, server, and rate-limit errors with bounded exponential backoff, jitter, and `Retry-After` support; non-transient stream errors still fail immediately.
59
+ - ChatGPT-authenticated Codex transport requests now retry transient SSE failures such as `server_is_overloaded`, service-unavailable, server, and rate-limit errors with bounded exponential backoff, jitter, and `Retry-After` support; non-transient stream errors still fail immediately.
24
60
 
25
61
  ### Fixed
26
62
 
@@ -30,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
30
66
 
31
67
  ### Added
32
68
 
33
- - Codex subscription provider with browser and device-code authentication via `/login`, using the installed `codex` CLI app-server and isolated Ness global credentials (never reads or writes `~/.codex`).
69
+ - Experimental Codex integration with ChatGPT browser and device-code authentication via `/login`, using the installed `codex` CLI app-server for authentication and isolated Ness global credentials (never reads or writes `~/.codex`). Model inference uses Ness's separate ChatGPT-authenticated Codex Responses transport.
34
70
  - Pluggable model provider layer (`ness_cli/provider/`) with shared registry, profile selection, and separate Codex and OpenRouter adapters/chat models.
35
71
  - Install scripts at `https://nessagent.dev/install.sh` (macOS/Linux) and `install.ps1` (Windows).
36
72
  - Persistent session names through the SDK `Session.set_name()` / `ThreadStore.set_thread_name()` APIs and the interactive `/rename <name>` command.
@@ -41,7 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
41
77
 
42
78
  ### Changed
43
79
 
44
- - `/login` is the primary provider onboarding path: choose Codex subscription or OpenRouter API key, switch active providers mid-session, and reconnect or log out from a dedicated picker.
80
+ - `/login` is the primary provider onboarding path: sign in to Codex with ChatGPT or configure an OpenRouter API key, switch active providers mid-session, and reconnect or log out from a dedicated picker.
45
81
  - `/status` labels subscription usage as `subscription` rather than estimating it as API spend.
46
82
  - TUI pickers now expand responsively to show up to 12 choices while retaining transcript space, with improved approval and question layouts.
47
83
  - **Breaking:** the SQLite `threads` table now requires a `name` column. Automatic database migrations are intentionally unsupported; back up or remove `.ness/threads/threads.db` before using this version. Removing it permanently discards saved threads unless they were backed up externally.
@@ -87,7 +123,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
87
123
  - SDK: LangGraph agent loop, built-in tools, permissions, memory, skills, hooks, MCP, compaction, reflection, and tracing.
88
124
  - CLI: interactive TUI (`ness`), headless print mode (`-p`), plan/act modes, git worktrees, global config, and `.ness/` project layout.
89
125
 
90
- [Unreleased]: https://github.com/Sagnnik/ness-agent/compare/v0.2.2...HEAD
126
+ [Unreleased]: https://github.com/Sagnnik/ness-agent/compare/v0.2.4...HEAD
127
+ [0.2.4]: https://github.com/Sagnnik/ness-agent/compare/v0.2.3...v0.2.4
128
+ [0.2.3]: https://github.com/Sagnnik/ness-agent/compare/v0.2.2...v0.2.3
91
129
  [0.2.2]: https://github.com/Sagnnik/ness-agent/compare/v0.2.1...v0.2.2
92
130
  [0.2.1]: https://github.com/Sagnnik/ness-agent/compare/v0.2.0...v0.2.1
93
131
  [0.2.0]: https://github.com/Sagnnik/ness-agent/compare/v0.1.0...v0.2.0
@@ -44,7 +44,8 @@ PACKAGING_SMOKE=1 uv run pytest -q -m packaging
44
44
 
45
45
  ## Pull requests
46
46
 
47
- 1. Please open an issue to propose features or major changes before submitting a PR so we can align on design early.
47
+ 1. Small PRs only — keep changes focused and minimal. Large PRs will not be accepted.
48
+ 2. Large feature requests — open an issue first to discuss the design before writing any code.
48
49
  2. Branch from `main` (e.g. `feat/cli-cron`, `fix/session-resume`).
49
50
  3. Keep changes focused; match existing code style in touched files.
50
51
  4. Ensure tests pass before opening a PR.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ness-agent
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Ness Agent is an experimental, hackable agent harness.
5
5
  Project-URL: Homepage, https://github.com/Sagnnik/ness-agent
6
6
  Project-URL: Documentation, https://github.com/Sagnnik/ness-agent/tree/main/docs
@@ -61,6 +61,7 @@ Ness Agent is an experimental, hackable coding-agent harness for engineers who w
61
61
  <p align="center">
62
62
  <img src="assets/ness_agent_sc.png" alt="NessAgent terminal UI showing project context, tool execution, and Act mode" width="100%">
63
63
  </p>
64
+ <p align="center"><a href="https://raw.githubusercontent.com/Sagnnik/ness-agent/main/assets/ness-demo6.mp4">Open the demo video</a></p>
64
65
  <p align="center"><em>NessAgent TUI in Act mode.</em></p>
65
66
 
66
67
  > **0.x experimental** — APIs may change until 1.0. See [CHANGELOG](https://github.com/Sagnnik/ness-agent/blob/main/CHANGELOG.md).
@@ -82,7 +83,6 @@ Ness Agent is an experimental, hackable coding-agent harness for engineers who w
82
83
  | **Ness Agent SDK** | LangGraph agent loop, built-in tools, permissions, memory, skills, hooks, MCP, compaction, reflection, tracing |
83
84
  | **Ness CLI** | Terminal UI (`ness`), plan/act modes, git worktrees, global config, `.ness/` project layout |
84
85
 
85
- Both are included in the `ness-agent` PyPI package. OpenRouter-compatible chat models, native tool-calling, cache-safe summary compaction, and filesystem-driven extension points under `.ness/`.
86
86
 
87
87
  ## Installation
88
88
 
@@ -108,10 +108,15 @@ uv tool install --upgrade ness-agent
108
108
  # or: pipx install ness-agent
109
109
  ```
110
110
 
111
- Launch `ness` and run `/login` to use either a Codex subscription or an
112
- OpenRouter API key. Codex sign-in uses the installed `codex` CLI's managed
113
- browser/device flow and stores credentials in Ness's isolated global config
114
- directory; it never reads or changes `~/.codex`.
111
+ Launch `ness` and run `/login` to sign in to Codex with ChatGPT or configure an
112
+ OpenRouter API key. Codex authentication uses the installed `codex` CLI
113
+ app-server's managed browser/device flow and stores credentials in Ness's
114
+ isolated global config directory; it never reads or changes `~/.codex`.
115
+
116
+ > [!NOTE]
117
+ > Ness's Codex model transport is experimental. Authentication and credential
118
+ > management are handled by Codex app-server, while Ness sends inference
119
+ > requests directly to the ChatGPT Codex Responses endpoint used by Codex CLI.
115
120
 
116
121
  For environment-based OpenRouter setup:
117
122
 
@@ -14,6 +14,7 @@ Ness Agent is an experimental, hackable coding-agent harness for engineers who w
14
14
  <p align="center">
15
15
  <img src="assets/ness_agent_sc.png" alt="NessAgent terminal UI showing project context, tool execution, and Act mode" width="100%">
16
16
  </p>
17
+ <p align="center"><a href="https://raw.githubusercontent.com/Sagnnik/ness-agent/main/assets/ness-demo6.mp4">Open the demo video</a></p>
17
18
  <p align="center"><em>NessAgent TUI in Act mode.</em></p>
18
19
 
19
20
  > **0.x experimental** — APIs may change until 1.0. See [CHANGELOG](https://github.com/Sagnnik/ness-agent/blob/main/CHANGELOG.md).
@@ -35,7 +36,6 @@ Ness Agent is an experimental, hackable coding-agent harness for engineers who w
35
36
  | **Ness Agent SDK** | LangGraph agent loop, built-in tools, permissions, memory, skills, hooks, MCP, compaction, reflection, tracing |
36
37
  | **Ness CLI** | Terminal UI (`ness`), plan/act modes, git worktrees, global config, `.ness/` project layout |
37
38
 
38
- Both are included in the `ness-agent` PyPI package. OpenRouter-compatible chat models, native tool-calling, cache-safe summary compaction, and filesystem-driven extension points under `.ness/`.
39
39
 
40
40
  ## Installation
41
41
 
@@ -61,10 +61,15 @@ uv tool install --upgrade ness-agent
61
61
  # or: pipx install ness-agent
62
62
  ```
63
63
 
64
- Launch `ness` and run `/login` to use either a Codex subscription or an
65
- OpenRouter API key. Codex sign-in uses the installed `codex` CLI's managed
66
- browser/device flow and stores credentials in Ness's isolated global config
67
- directory; it never reads or changes `~/.codex`.
64
+ Launch `ness` and run `/login` to sign in to Codex with ChatGPT or configure an
65
+ OpenRouter API key. Codex authentication uses the installed `codex` CLI
66
+ app-server's managed browser/device flow and stores credentials in Ness's
67
+ isolated global config directory; it never reads or changes `~/.codex`.
68
+
69
+ > [!NOTE]
70
+ > Ness's Codex model transport is experimental. Authentication and credential
71
+ > management are handled by Codex app-server, while Ness sends inference
72
+ > requests directly to the ChatGPT Codex Responses endpoint used by Codex CLI.
68
73
 
69
74
  For environment-based OpenRouter setup:
70
75
 
@@ -12,6 +12,20 @@ Ness Agent is split into a reusable **SDK** and a **coding CLI adapter** (Ness).
12
12
 
13
13
  See also: [SDK guide](sdk.md) · [CLI guide](cli.md) · [Configuration](configuration.md)
14
14
 
15
+ ### Runtime ownership
16
+
17
+ `NessAgent` represents one project/application runtime. It owns resolved defaults and services that are safe or useful to share across that project's sessions. `NessAgent.session()` takes a selective effective-config snapshot so live threads do not mutate one another.
18
+
19
+ | Scope | State |
20
+ |------|------|
21
+ | Agent/project | Thread persistence, memory backend, hooks, skill loader, tool definitions and MCP catalog, persistent permission file/lock, tracer, pricing, and defaults inherited by future sessions |
22
+ | Session/thread | Effective main/reflection models and options, temporary permission rules, active MCP tools and binding cache, cost totals, graph/checkpointer, event queue, cancellation token, mode, metadata, and adapter callbacks |
23
+ | Turn | User input, optional mode/skill overrides, usage aggregate, streamed events, and active cancellation state |
24
+
25
+ Live model usage is recorded in the session tracker and propagated once to the agent aggregate. Durable replay updates only the session tracker, so resuming a thread does not look like newly incurred provider spend. Persistent permission choices are shared through `permissions.json`; temporary `session` choices stay on the session-local view. Tool definitions are shared, while deferred MCP activation is session-local.
26
+
27
+ The Ness CLI keeps one `CodingSession` runtime per live thread. `/new` and `/threads` may therefore leave one turn running while another thread becomes selected. A `/config` model/provider/reasoning change rebuilds the selected runtime and updates agent defaults for future runtimes; already-live sibling threads remain pinned.
28
+
15
29
  ### MCP boundary
16
30
 
17
31
  The SDK's `MCPRuntime` accepts fully resolved stdio or HTTP server specifications and owns connections, session lifecycle, tool discovery, LangChain tool conversion, calls, and structured connection state. It has no project-file, terminal, trust, or credential-storage policy, so it can be embedded in domain-specific or domain-agnostic applications.
@@ -55,6 +69,13 @@ Session tool tiers (same set bound in both modes):
55
69
  - Advanced: `spawn_subagent`
56
70
  - Loaded MCP tools: any `mcp__*` tool activated this session (deferred by default; load via `search_tools`/`add_tools` or `/mcp <server> [tool]`)
57
71
 
72
+ For vision-capable sessions, `read` accepts PNG, JPEG, WebP, GIF, PPM, BMP,
73
+ and TIFF files and returns a normalized image block to the model. Images are
74
+ oriented from EXIF metadata, resized to a 2000px maximum long edge, encoded as
75
+ PNG, and rejected if the normalized payload exceeds 5 MB. Text-only sessions
76
+ receive an explicit omission marker. PDFs and videos are not passed directly;
77
+ render PDF pages or extract video frames to a supported raster format first.
78
+
58
79
  ---
59
80
 
60
81
  ## Memory
@@ -92,8 +113,8 @@ Compaction is a cache-safe fork of the main conversation. At every boundary befo
92
113
  | 70-80% | Warn that summary compaction is approaching |
93
114
  | >= 80% | Summarize completed history |
94
115
 
95
- Compaction also runs earlier when necessary to preserve `COMPACTION_BUFFER_TOKENS` for the instruction and capped summary output. The latest unanswered user turn and its complete assistant/tool trajectory remain verbatim; only completed history is summarized. Old L3 reminders are visible to the cache-safe fork but explicitly excluded from summary semantics. The replacement branch contains one human `<compacted-history>` message, the active suffix, and one newly rendered current L3 reminder.
116
+ Compaction also runs earlier when necessary to preserve `COMPACTION_BUFFER_TOKENS` for the instruction and capped summary output. Normally the latest unanswered user turn and its assistant/tool trajectory remain verbatim. If that continuation itself exceeds about 40% of usable context (clamped between 8k and 65k tokens), Ness summarizes its older work and retains a coherent recent suffix without splitting a tool-call batch from its results. Old L3 reminders are visible to the cache-safe fork but explicitly excluded from summary semantics. The replacement branch contains one human `<compacted-history>` message, the retained active suffix, and one newly rendered current L3 reminder.
96
117
 
97
118
  Image-bearing user messages remain structured in live and replayed canonical history after they are answered. They are removed only when their completed turn is replaced by summary compaction (or when vision is explicitly disabled).
98
119
 
99
- Compaction is a separate graph node between `START`/`tools` and `agent`, so it never runs during tool execution and its state checkpoints before the next model request. Summary failures preserve the original history and may continue below the safety boundary; at the boundary the turn stops rather than using a lossy fallback. `/compact` forces this process at the next model boundary.
120
+ Compaction is a separate graph node between `START`/`tools` and `agent`, so it never runs during tool execution and its state checkpoints before the next model request. Summary-call usage is isolated from the parent agent call so it cannot distort later context-pressure accounting. Summary failures preserve the original history and may continue below the safety boundary; at the boundary the turn stops rather than using a lossy fallback. If no safe retained suffix can fit, the turn fails explicitly instead of sending an oversized request. `/compact` forces this process at the next model boundary.
@@ -1,6 +1,6 @@
1
1
  # Ness CLI
2
2
 
3
- **Ness** is the interactive coding-agent CLI shipped with Ness Agent. It supports Codex subscription and OpenRouter models, plan/act modes, filesystem-driven extension points under `.ness/`, and a full TUI for approvals, thread history, and configuration.
3
+ **Ness** is the interactive coding-agent CLI shipped with Ness Agent. It supports plan/act modes, filesystem-driven extension points under `.ness/`, and a full TUI for approvals, thread history, and configuration.
4
4
 
5
5
  See also: [Configuration](configuration.md) · [Architecture](architecture.md) · [SDK](sdk.md)
6
6
 
@@ -24,8 +24,8 @@ ness
24
24
 
25
25
  `/init` creates project `.ness/` (dirs, permissions, hooks, mcp, default agent profiles, empty `NESS.md`) and ensures global config (`USER.md`, `instructions/`, `plans/<slug>/`).
26
26
 
27
- Or skip the env var and run `/login`. Choose Codex subscription for managed
28
- browser/device authentication, or OpenRouter for a masked API-key prompt. Device-code
27
+ Or skip the env var and run `/login`. Choose Codex to sign in with ChatGPT
28
+ using managed browser/device authentication, or OpenRouter/OpenCode Go for a masked API-key prompt. Device-code
29
29
  login must first be enabled in ChatGPT **Settings > Security** by turning on
30
30
  **Device code authorization for Codex**; browser login does not require that setting.
31
31
  Selecting a connected provider makes it active and exposes only **Reconnect** and
@@ -246,19 +246,19 @@ Shift+Tab toggles plan/act mode without rebuilding the graph or invalidating the
246
246
 
247
247
  - `/help`: show the command reference.
248
248
  - `/login`: authenticate or manage model providers in a dedicated picker. Selecting a connected provider activates it and offers Reconnect/Log out; selecting a disconnected provider starts authentication immediately. Provider changes rebuild the model while preserving the thread.
249
- - `/config`: edit provider keys/endpoints, model/reasoning, behavior toggles, compaction budgets, and advanced options (persisted to global `configs.json` / `secrets.json`).
249
+ - `/config`: edit provider keys/endpoints, model/reasoning, behavior toggles, compaction budgets, and advanced options (persisted to global `configs.json` / `secrets.json`). Model/provider/reasoning changes rebuild the selected thread and become defaults for future threads; other live thread runtimes keep their existing model configuration.
250
250
  - `/exit` or `/quit`: end the session.
251
251
 
252
252
  **Session**
253
253
 
254
- - `/status`: show provider authentication, account email/tier, every available usage-limit window (including weekly), reset times/credits, and session token/cache/cost stats. Subscription calls are labeled `subscription` rather than estimated as API spend.
254
+ - `/status`: show provider authentication, account email/tier, every available usage-limit window (including OpenCode Go's rolling 5-hour, weekly, and monthly windows), reset times/credits, and the selected session's token/cache/cost stats. Subscription calls are labeled `subscription` rather than estimated as API spend.
255
255
  - `/threads`: open a scrollable saved-thread picker, ordered by recent updates and prefixed with local `YYYY-MM-DD HH:mm` timestamps. Threads with active turns show an animated working indicator; switching away does not interrupt them.
256
256
  - `/rename <name>`: set or update the current session's persistent display name (1–80 characters; requires thread autosave).
257
257
  - `/fork`: choose a human message, copy the conversation state before it into a child thread, and prefill that message for editing. Forking copies session memory/checkpoints but leaves current working-tree files unchanged.
258
258
  - `/goal <objective>`: run up to three worker attempts, each followed by an isolated read-only judge. Failed verdicts become repair instructions for the next attempt.
259
259
  - `/save`: archive the current thread with a headline summary.
260
260
  - `/new`: archive and start a fresh thread. During an active turn, the running thread stays in the background and the new thread starts independently.
261
- - `/compact`: request a cache-safe summary at the next model boundary; the active user/tool turn remains verbatim.
261
+ - `/compact`: request a cache-safe summary at the next model boundary; the active user/tool turn remains verbatim unless it exceeds the retained-suffix budget, in which case older in-turn work is summarized and a coherent recent suffix is kept.
262
262
  - `/reflection`: immediately reflect on conversation messages added since the last successful reflection and update session memory.
263
263
  - `/export <path.html>`: write the current durable session as a self-contained, interactive HTML transcript. The export retains events from before compactions, includes an in-page normalized JSONL download, omits pasted image bytes, and refuses to overwrite an existing file. Quote paths that contain spaces.
264
264
 
@@ -310,7 +310,7 @@ Event kinds stored in `events.payload` (session threads only):
310
310
 
311
311
  `/threads` lists user `session-*` threads only. Each row starts with its locally converted update datetime and uses an explicit `/rename` name when present, then falls back to the archived summary or first user message. The original conversation shows `×N` when it has forks; each fork shows `fork #k` in creation order. Fork lineage is stored explicitly on the thread row; inherited usage remains in the copied event history but is excluded from the child thread's cost totals. Subagent trajectories are not stored in `events`; subagent LLM usage rolls up into the parent session's `threads` aggregates. Subagent outputs are stored in the `subagents` table.
312
312
 
313
- Selecting a thread rebuilds user messages, assistant tool-call turns, and tool results from saved events. The startup `--resume <thread_id>` flag remains available for automation. `spawn_subagent` tool output is supplemented from linked subagent outputs when available.
313
+ Selecting an idle saved thread rebuilds user messages, assistant tool-call turns, and tool results from saved events. A thread that is already live keeps its own model, temporary approvals, MCP activation, graph, cancellation state, and cost total when selected again. The startup `--resume <thread_id>` flag remains available for automation. `spawn_subagent` tool output is supplemented from linked subagent outputs when available.
314
314
 
315
315
  When a thread contains a successful new-format `compaction_llm` checkpoint, resume starts from its summary and replays only raw events after `source_event_seq`. Raw conversation events remain available for audit, rollback, and forks; L3 reminder messages are never written to the event log.
316
316
 
@@ -68,9 +68,10 @@ Project `.env` files are not loaded or migrated for Ness application settings. E
68
68
  Use `/login` to authenticate, activate, reconnect, or log out of a model provider.
69
69
  Selecting a connected provider activates it and opens its Reconnect/Log out menu;
70
70
  selecting a disconnected provider starts authentication without an extra Connect step.
71
- OpenRouter keys are stored in `secrets.json`. Codex subscription credentials
72
- are managed by the system `codex` CLI under `<NESS_AGENT_CONFIG_DIR>/codex/`
73
- with file credential storage forced; Ness does not reuse `~/.codex`.
71
+ OpenRouter and OpenCode Go keys are stored separately in `secrets.json`. ChatGPT credentials for Codex
72
+ are managed by the system `codex` CLI app-server under
73
+ `<NESS_AGENT_CONFIG_DIR>/codex/` with file credential storage forced; Ness
74
+ does not reuse `~/.codex`.
74
75
  Codex device-code login additionally requires **Device code authorization for
75
76
  Codex** to be enabled in ChatGPT **Settings > Security**. Use browser login if
76
77
  that account setting is unavailable.
@@ -79,6 +80,12 @@ Provider-specific model and reasoning choices are nested under
79
80
  `provider_profiles` in `configs.json`, so switching providers restores each
80
81
  provider's last selection. Legacy top-level OpenRouter settings remain valid.
81
82
 
83
+ In the concurrent TUI, saved configuration is the default for new thread
84
+ runtimes. Changing the model, provider, or reasoning effort through `/config`
85
+ also rebuilds the currently selected thread, but it does not mutate sibling
86
+ threads that are already live. Selecting one of those threads later restores
87
+ its pinned runtime configuration.
88
+
82
89
  ---
83
90
 
84
91
  ## Environment variables
@@ -87,8 +94,8 @@ All except `NESS_DIR` are also editable via `/config` in the Ness TUI.
87
94
 
88
95
  | Variable | Description |
89
96
  |----------|-------------|
90
- | `MODEL_PROVIDER` | Active provider (`openrouter` by default, or `codex`) |
91
- | `MODEL_NAME` | Model passed to `ChatOpenRouter` (`deepseek/deepseek-v4-flash` by default) |
97
+ | `MODEL_PROVIDER` | Active provider (`openrouter` by default, `codex`, or `opencode`) |
98
+ | `MODEL_NAME` | Active provider model ID (`deepseek/deepseek-v4-flash` by default) |
92
99
  | `REFLECTION_MODEL_NAME` | Model for background session-memory reflection (defaults to `MODEL_NAME`) |
93
100
  | `ENABLE_APPROVAL` | Require approval for destructive tools |
94
101
  | `AUTO_SAVE_THREADS` | Write thread events to `.ness/threads/` |
@@ -105,6 +112,7 @@ All except `NESS_DIR` are also editable via `/config` in the Ness TUI.
105
112
  | `GOAL_MAX_ATTEMPTS` | Maximum worker/judge attempts for `/goal` (default `3`) |
106
113
  | `OPENAI_BASE_URL` | Optional custom OpenAI-compatible base URL |
107
114
  | `OPENAI_API_KEY` | Provider API key (also stored in `secrets.json` via `/config`) |
115
+ | `OPENCODE_GO_API_KEY` / `OPENCODE_API_KEY` | OpenCode Go subscription key (also stored separately in `secrets.json`) |
108
116
  | `FORMAT_ON_WRITE` | Auto-format supported file types after writes (default `true`) |
109
117
  | `NESS_DIR` | Project config directory (default `.ness`) |
110
118
  | `NESS_AGENT_CONFIG_DIR` | Override global config root |
@@ -123,9 +131,4 @@ advanced options; provider-only fields are hidden when they do not apply.
123
131
 
124
132
  The `/config` model picker reads the active provider's catalog. OpenRouter's
125
133
  global disk cache is reused for 24 hours with a packaged offline fallback;
126
- Codex models are supplied by `codex app-server` for the signed-in account.
127
-
128
- Codex access tokens are refreshed through `account/read` shortly before JWT
129
- expiry and once after an HTTP 401. Network, rate-limit, and server failures do
130
- not trigger credential refresh. The subscription Responses transport is kept
131
- inside `src/ness_cli/provider/codex/` because that endpoint is experimental.
134
+ `codex app-server` handles ChatGPT authentication and credential management for the signed-in account. Ness performs model inference separately through its experimental ChatGPT-authenticated Codex Responses transport.
@@ -1,6 +1,6 @@
1
1
  # SDK API reference
2
2
 
3
- This reference covers the symbols exported by `ness_agent.__all__` in the 0.2.2 source tree. It is intentionally an API map rather than a second tutorial: start with the [SDK guide](sdk.md) for the shortest working example, then use this page when choosing a seam to own.
3
+ This reference covers the symbols exported by `ness_agent.__all__` in the 0.2.4 source tree. It is intentionally an API map rather than a second tutorial: start with the [SDK guide](sdk.md) for the shortest working example, then use this page when choosing a seam to own.
4
4
 
5
5
  > **0.x experimental.** Names and signatures below describe the current public surface; pin a version before relying on it in production.
6
6
 
@@ -15,13 +15,18 @@ agent.session(*, thread_id: str, mode: str | None = None,
15
15
  metadata: Mapping[str, Any] | None = None,
16
16
  git_available: bool | None = None, vision: bool | None = None,
17
17
  on_plan_turn: PlanTurnHandler | None = None,
18
- on_interrupt: InterruptHandler | None = None) -> Session
18
+ on_interrupt: InterruptHandler | None = None,
19
+ model: BaseChatModel | None = None,
20
+ reflection_model: BaseChatModel | None | object = _UNSET) -> Session
21
+ agent.configure_default_models(*, model: BaseChatModel,
22
+ reflection_model: BaseChatModel | None,
23
+ context_window: int | None) -> None
19
24
  agent.new_thread_id(prefix: str = "session") -> str
20
25
  ```
21
26
 
22
- The top-level SDK entry point owns a resolved shared configuration and creates an isolated `Session` per conversation thread. `model` is a LangChain `BaseChatModel`; `prompt` accepts `PromptLayers`, `PromptLayersConfig`, or a mapping. With `tools=None`, the SDK resolves its built-in tool set. `config` exposes the resolved `NessAgentConfig` when an application needs to inspect the constructed backends.
27
+ The top-level SDK entry point owns project services and resolved defaults, then creates an isolated effective configuration for each `Session`. `model` is a LangChain `BaseChatModel`; `prompt` accepts `PromptLayers`, `PromptLayersConfig`, or a mapping. With `tools=None`, the SDK resolves its built-in tool set. `agent.config` exposes project defaults and the live aggregate cost tracker; `session.config` exposes the effective session fork.
23
28
 
24
- `session()` accepts optional per-thread metadata for the L3 overlay. `vision=True` sends supplied image URLs; `False` drops them to text and emits a warning event; `None` leaves content shape untouched. The two callback hooks live on a session, not on the shared agent, so concurrent threads do not overwrite each other.
29
+ `session()` accepts optional per-thread metadata for the L3 overlay and effective main/reflection model overrides. `vision=True` sends supplied image URLs; `False` drops them to text and emits a warning event; `None` leaves content shape untouched. The two callback hooks live on a session, not on the shared agent, so concurrent threads do not overwrite each other. `configure_default_models()` changes inheritance for sessions created later; it does not rebuild existing sessions.
25
30
 
26
31
  ```python
27
32
  agent = NessAgent(model=model, prompt=PromptLayersConfig())
@@ -74,10 +79,19 @@ await session.run(message: str, *, images: Sequence[str] | None = None,
74
79
 
75
80
  async for event in session.stream(message: str, *, images=None,
76
81
  active_skills=None, mode=None): ...
82
+
83
+ session.config -> NessAgentConfig
84
+ session.cost_tracker -> CostTracker
85
+ session.configure_models(*, model: BaseChatModel,
86
+ reflection_model: BaseChatModel | None,
87
+ context_window: int | None,
88
+ vision: bool | None) -> None
77
89
  ```
78
90
 
79
91
  `run()` collects one complete turn. It returns assistant text, an aggregate `usage_total` over every model call in the turn, the current todos, and every intermediate event. `stream()` yields those `SessionEvent` records as the graph advances. `mode=` is a one-turn override; otherwise the session’s current `act` or `plan` mode is used.
80
92
 
93
+ Each session owns a selective shallow fork of the agent configuration. Mutable runtime state—models and options, temporary permission rules, active MCP tools, and cost totals—is isolated. Project services such as thread persistence, hooks, memory, and the underlying permission/tool catalogs remain shared. `session.config` exposes the effective session view; `agent.config` remains the defaults inherited by future sessions plus the live agent-level cost aggregate.
94
+
81
95
  Important control and inspection methods:
82
96
 
83
97
  | Method | Purpose |
@@ -87,6 +101,7 @@ Important control and inspection methods:
87
101
  | `bootstrap(messages)` | Seed prior messages into the next turn once; use for resume or rollback replay. |
88
102
  | `cancel()` / `is_cancelled()` | Request and inspect cooperative cancellation of the active stream. |
89
103
  | `request_compact()` | Request compaction on the next turn. |
104
+ | `configure_models(...)` | Replace this session's effective main/reflection models and context settings, then rebuild its graph. |
90
105
  | `active_skills(names)` / `stage_skills(names)` | Replace or append one-shot skills for the next turn. |
91
106
  | `get_state()`, `get_messages()`, `get_todos()` | Async snapshots of the checkpointed state. |
92
107
  | `preview_context(mode=None) -> ContextPreview` | Assemble L0–L3 for debugging without running the model. |
@@ -175,23 +190,29 @@ Sources: `src/ness_agent/context/overlay.py`, `context/coding_overlay.py`, and `
175
190
 
176
191
  ```python
177
192
  ToolRegistry(tools: Iterable[BaseTool] | None = None, *, include: Iterable[str] | None = None)
193
+ registry.fork_for_session() -> ToolRegistry
178
194
  coding_tools(*, include: list[str] | None = None) -> ToolRegistry
179
195
  ```
180
196
 
181
197
  The registry owns known tools and the currently bound active set. Core reads are `active_tools`, `tool_map()`, `tool_names()`, `all_tools()`, and `deferred_tool_names()`. Call `bind_model(model)` to return a tool-bound chat model, and `sync()` after a structural change. `register_dynamic(tools)` adds dynamic tools as known but inactive; `activate_mcp(names)` and `deactivate_mcp(names)` return `(changed, unknown)` lists and adjust the active MCP set.
182
198
 
199
+ `fork_for_session()` creates a registry view that shares tool definitions and the deferred MCP catalog while keeping its active MCP names, include filter, binding cache, and local generation independent. Structural catalog additions remain visible to all session views; activating a deferred MCP tool affects only that session.
200
+
183
201
  `set_mcp_catalog()` and `deferred_mcp_summary()` maintain the lightweight deferred-MCP prompt catalog. `is_destructive(name, args)` and `is_read_only(name, args)` expose the registry’s policy classification. `coding_tools()` is the small convenience factory for name-selected SDK tools.
184
202
 
185
- The default tool list includes file read/write/delete/edit/glob, search, web fetch/search, shell, todos, tool discovery, subagents, questions, and skill viewing. It is not an API guarantee for every named tool; configure an explicit tool sequence when a host application needs a narrower contract.
203
+ The default tool list includes file read/write/delete/edit/glob, search, web fetch/search, shell, todos, tool discovery, subagents, questions, and skill viewing. In vision-capable sessions, `read` normalizes supported raster files and returns structured image content; PDFs and videos must first be rendered or split into raster frames. Image payloads are redacted from durable and display-facing events. This is not an API guarantee for every named tool; configure an explicit tool sequence when a host application needs a narrower contract.
186
204
 
187
205
  ### `PermissionStore`
188
206
 
189
207
  ```python
190
208
  PermissionStore(*, ness_dir: Path = Path(".ness"), project_root: Path | None = None)
209
+ store.fork_for_session() -> PermissionStore
191
210
  ```
192
211
 
193
212
  The file-backed policy store validates paths under the project root and resolves tool calls to `allow`, `deny`, or `ask` decisions. The main public operations are `check(tool, args)`, `check_with_rule(tool, args)`, `pattern_key(tool, args)`, `default_rule_for(tool, args)`, `persist_rule(...)`, `remove_rule(bucket, index)`, `list_rules()`, and `clear_session_rules()`. Use it when embedding an operator-approved policy rather than bypassing the tool executor.
194
213
 
214
+ `fork_for_session()` shares the persistent `permissions.json` path and synchronization lock while copying temporary allow/deny rules. A `session` decision therefore affects one session; `always`/`never` decisions are atomically persisted and become visible to every session on the project.
215
+
195
216
  ### `Hook` and `HookRunner`
196
217
 
197
218
  ```python
@@ -296,11 +317,15 @@ Sources: `src/ness_agent/memory.py` and `persistence.py`.
296
317
  PricingDict = dict[str, tuple[float, float, float]]
297
318
  CostTracker(pricing: PricingDict | None = None,
298
319
  estimate_cost: Callable[[str, int, int, int], float | None] | None = None)
320
+ tracker.fork_for_session() -> CostTracker
299
321
  tracker.add(usage, model_name=None, response_metadata=None) -> TokenUsage | None
322
+ tracker.restore(usage, model_name=None, response_metadata=None) -> TokenUsage | None
300
323
  ```
301
324
 
302
325
  `TokenUsage` is a slots dataclass with model, input/uncached/cached/output/total tokens, `cost_usd`, `cost_source`, cache-hit rate, and calls. `as_dict()` serializes it. `CostTracker.add()` ingests provider usage and prefers provider-reported cost, then a supplied estimator, then a matching substring key in `pricing`. Pricing triples are USD per million tokens: `(input, output, cache_read_ratio)`.
303
326
 
327
+ `CostTracker.fork_for_session()` returns an empty tracker with shared pricing. New usage also rolls into the parent tracker; `restore()` loads durable historical usage locally without changing that live aggregate. Read per-thread totals from `session.cost_tracker` and current-process agent totals from `agent.config.cost_tracker`.
328
+
304
329
  Use `for_model(model)`, `total()`, `models()`, or the scalar aggregate properties (`input_tokens`, `output_tokens`, `total_tokens`, `calls`, `cost_usd`, `cache_hit_rate`, `total_cost_usd`) to inspect accumulated data. `report()` returns a text report.
305
330
 
306
331
  ### `TracingConfig`, `Tracer`, `Span`, and implementations
@@ -56,6 +56,48 @@ asyncio.run(main())
56
56
 
57
57
  `tools=` accepts a mix of `BaseTool` instances, plain callables (auto-wrapped), and built-in name strings (`"read"`, `"grep"`, `"shell"`, …). Pass `overlay=NoOverlay()` to drop L3 entirely. Instruction bodies are importable — e.g. `from ness_agent.instructions import L0_HARNESS, PLAN_MODE`.
58
58
 
59
+ In a vision-capable session, the built-in `read` tool returns supported raster
60
+ images (PNG, JPEG, WebP, GIF, PPM, BMP, and TIFF) as structured image content.
61
+ It applies EXIF orientation, limits the long edge to 2000px, re-encodes to PNG,
62
+ and enforces a 5 MB normalized-payload ceiling. With `vision=False`, the model
63
+ receives a visible omission marker instead. PDFs and videos must first be
64
+ rendered or have frames extracted to a supported raster format. Persisted
65
+ events, hooks, traces, and display events receive a redacted text form rather
66
+ than the base64 image payload.
67
+
68
+ ### Project agents and concurrent sessions
69
+
70
+ A `NessAgent` is a project-scoped runtime: it owns shared persistence, memory, hooks, skill and tool catalogs, tracing, pricing, and defaults. Each call to `agent.session(...)` creates a separate effective runtime with its own graph/checkpointer, model fields, copied options, temporary permission rules, active MCP set, cancellation state, and cost tracker.
71
+
72
+ ```python
73
+ agent = NessAgent(model=default_model, prompt=PromptLayersConfig())
74
+
75
+ first = agent.session(thread_id="thread-a")
76
+ second = agent.session(thread_id="thread-b", model=specialized_model)
77
+
78
+ await asyncio.gather(
79
+ first.run("inspect the API"),
80
+ second.run("inspect the database"),
81
+ )
82
+ ```
83
+
84
+ Use a different `Session` for each concurrent thread; two simultaneous `run()`/`stream()` calls on the same `Session` are unsupported. Use a different `NessAgent` for an unrelated project because project paths and shared stores belong to the agent.
85
+
86
+ Changing defaults affects future sessions only:
87
+
88
+ ```python
89
+ agent.configure_default_models(
90
+ model=new_default,
91
+ reflection_model=new_reflection_default,
92
+ context_window=200_000,
93
+ )
94
+
95
+ # Existing sessions remain pinned. This session inherits the new defaults.
96
+ third = agent.session(thread_id="thread-c")
97
+ ```
98
+
99
+ To deliberately change one live session, call `session.configure_models(...)`. Read thread usage from `session.cost_tracker`; `agent.config.cost_tracker` is the live current-process aggregate across sessions. Replayed history is restored into the session tracker without being counted as new aggregate spend.
100
+
59
101
  ### What the host owns
60
102
 
61
103
  Bare `Session.run` is the turn engine only. Your application still needs to:
@@ -0,0 +1,68 @@
1
+ # Harbor evals
2
+
3
+ The default adapter runs Ness through OpenRouter. The `evals/codex` adapter runs
4
+ the same Ness SDK through the ChatGPT-authenticated Codex Responses transport.
5
+
6
+ Install the eval dependencies:
7
+
8
+ ```bash
9
+ uv sync --group evals
10
+ ```
11
+
12
+ Run one selected Terminal-Bench 2.1 task on Modal:
13
+
14
+ ```bash
15
+ PYTHONPATH=. uv run --group evals harbor run \
16
+ -d terminal-bench/terminal-bench-2-1 \
17
+ --include-task-name terminal-bench/headless-terminal \
18
+ --agent evals.ness_harbor_agent:NessAgent \
19
+ --model openrouter/deepseek/deepseek-v4-flash \
20
+ --env modal \
21
+ --env-file .env \
22
+ --jobs-dir evals/jobs \
23
+ --n-concurrent 3 \
24
+ --n-attempts 3
25
+ ```
26
+
27
+ Use another `--include-task-name` value to select a different task. Repeat the
28
+ flag to run several named tasks in one job. `--n-concurrent` is the number of concurrent sandboxes while
29
+ `--n-attempts` is the number of attempts on the same task. Rewards are averaged by the number of attempts.
30
+
31
+ Or run it with the config file:
32
+ ```bash
33
+ PYTHONPATH=. uv run --group evals harbor run \
34
+ -c evals/configs/tb-single-task.yaml \
35
+ --env-file .env
36
+ ```
37
+
38
+ To run the Ness SDK through the ChatGPT-authenticated Codex model, use the
39
+ separate Codex config. `CODEX_AUTH_JSON=true` makes the adapter read
40
+ `~/.codex/auth.json` on the host, upload it only for the agent phase, and remove
41
+ the temporary copy when the trial ends:
42
+
43
+ ```bash
44
+ CODEX_AUTH_JSON=true \
45
+ PYTHONPATH=. uv run --group evals harbor run \
46
+ -c evals/configs/tb-single-task-codex.yaml \
47
+ --env-file .env
48
+ ```
49
+ The auth file is not committed and must not be placed under `evals/jobs`.
50
+
51
+ Codex subscription runs attach an API-equivalent cost estimate to each usage
52
+ event. The standard short-context rates (USD per 1M tokens) are:
53
+
54
+ | Model | Input | Cached input | Output | Cache write |
55
+ | --- | ---: | ---: | ---: | ---: |
56
+ | `gpt-5.6-sol` | $4.00 | $0.40 | $20.00 | $5.00 |
57
+ | `gpt-5.6-terra` | $2.00 | $0.20 | $12.00 | $2.50 |
58
+ | `gpt-5.6-luna` | $0.20 | $0.02 | $1.20 | $0.25 |
59
+
60
+ These mirror the [OpenAI API pricing schedule](https://developers.openai.com/api/docs/pricing)
61
+ for estimation only; they are not ChatGPT subscription charges. Prompts over
62
+ 272K input tokens use the long-context multipliers from that schedule.
63
+
64
+ If you want to view the jobs info:
65
+ ```bash
66
+ harbor view jobs
67
+ ```
68
+ and visit `localhost:8080`