hrns 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. hrns-0.0.1/.gitignore +17 -0
  2. hrns-0.0.1/LICENSE +21 -0
  3. hrns-0.0.1/PKG-INFO +262 -0
  4. hrns-0.0.1/README.md +182 -0
  5. hrns-0.0.1/pyproject.toml +103 -0
  6. hrns-0.0.1/src/hrns/__init__.py +13 -0
  7. hrns-0.0.1/src/hrns/client/__init__.py +120 -0
  8. hrns-0.0.1/src/hrns/client/__main__.py +10 -0
  9. hrns-0.0.1/src/hrns/client/_version.py +5 -0
  10. hrns-0.0.1/src/hrns/client/attachments.py +167 -0
  11. hrns-0.0.1/src/hrns/client/bridge.py +250 -0
  12. hrns-0.0.1/src/hrns/client/bus.py +58 -0
  13. hrns-0.0.1/src/hrns/client/catalog.py +275 -0
  14. hrns-0.0.1/src/hrns/client/clean.py +174 -0
  15. hrns-0.0.1/src/hrns/client/cli.py +947 -0
  16. hrns-0.0.1/src/hrns/client/client.py +432 -0
  17. hrns-0.0.1/src/hrns/client/connection.py +197 -0
  18. hrns-0.0.1/src/hrns/client/constants.py +47 -0
  19. hrns-0.0.1/src/hrns/client/errors.py +98 -0
  20. hrns-0.0.1/src/hrns/client/events.py +185 -0
  21. hrns-0.0.1/src/hrns/client/extension.py +299 -0
  22. hrns-0.0.1/src/hrns/client/extensions_api.py +242 -0
  23. hrns-0.0.1/src/hrns/client/headless.py +328 -0
  24. hrns-0.0.1/src/hrns/client/interactions.py +374 -0
  25. hrns-0.0.1/src/hrns/client/launch.py +159 -0
  26. hrns-0.0.1/src/hrns/client/local.py +187 -0
  27. hrns-0.0.1/src/hrns/client/payloads.py +129 -0
  28. hrns-0.0.1/src/hrns/client/profiles.py +301 -0
  29. hrns-0.0.1/src/hrns/client/renderers.py +100 -0
  30. hrns-0.0.1/src/hrns/client/session.py +377 -0
  31. hrns-0.0.1/src/hrns/client/transport.py +523 -0
  32. hrns-0.0.1/src/hrns/client/tui/__init__.py +1 -0
  33. hrns-0.0.1/src/hrns/client/tui/app.py +860 -0
  34. hrns-0.0.1/src/hrns/client/tui/approval.py +543 -0
  35. hrns-0.0.1/src/hrns/client/tui/blocks.py +305 -0
  36. hrns-0.0.1/src/hrns/client/tui/chat/__init__.py +1 -0
  37. hrns-0.0.1/src/hrns/client/tui/chat/actions.py +285 -0
  38. hrns-0.0.1/src/hrns/client/tui/chat/capabilities.py +470 -0
  39. hrns-0.0.1/src/hrns/client/tui/chat/chrome.py +157 -0
  40. hrns-0.0.1/src/hrns/client/tui/chat/commands.py +253 -0
  41. hrns-0.0.1/src/hrns/client/tui/chat/connection.py +93 -0
  42. hrns-0.0.1/src/hrns/client/tui/chat/model.py +464 -0
  43. hrns-0.0.1/src/hrns/client/tui/chat/prompts.py +645 -0
  44. hrns-0.0.1/src/hrns/client/tui/chat/screen.py +887 -0
  45. hrns-0.0.1/src/hrns/client/tui/chat/session.py +261 -0
  46. hrns-0.0.1/src/hrns/client/tui/choice_keys.py +55 -0
  47. hrns-0.0.1/src/hrns/client/tui/commands.py +96 -0
  48. hrns-0.0.1/src/hrns/client/tui/completion.py +97 -0
  49. hrns-0.0.1/src/hrns/client/tui/composer.py +247 -0
  50. hrns-0.0.1/src/hrns/client/tui/connection_screen.py +650 -0
  51. hrns-0.0.1/src/hrns/client/tui/dialogs.py +1002 -0
  52. hrns-0.0.1/src/hrns/client/tui/extensions.py +138 -0
  53. hrns-0.0.1/src/hrns/client/tui/formatting.py +77 -0
  54. hrns-0.0.1/src/hrns/client/tui/local.py +332 -0
  55. hrns-0.0.1/src/hrns/client/tui/messages.py +58 -0
  56. hrns-0.0.1/src/hrns/client/tui/panels/__init__.py +5 -0
  57. hrns-0.0.1/src/hrns/client/tui/panels/activity.py +57 -0
  58. hrns-0.0.1/src/hrns/client/tui/panels/capability.py +373 -0
  59. hrns-0.0.1/src/hrns/client/tui/panels/mcp.py +219 -0
  60. hrns-0.0.1/src/hrns/client/tui/panels/session.py +243 -0
  61. hrns-0.0.1/src/hrns/client/tui/panels/side.py +85 -0
  62. hrns-0.0.1/src/hrns/client/tui/panels/todo.py +62 -0
  63. hrns-0.0.1/src/hrns/client/tui/screen_base.py +23 -0
  64. hrns-0.0.1/src/hrns/client/tui/state.py +774 -0
  65. hrns-0.0.1/src/hrns/client/tui/status.py +277 -0
  66. hrns-0.0.1/src/hrns/client/tui/tool_views.py +404 -0
  67. hrns-0.0.1/src/hrns/client/tui/transcript.py +818 -0
  68. hrns-0.0.1/src/hrns/client/turn.py +169 -0
  69. hrns-0.0.1/src/hrns/client/updates.py +190 -0
  70. hrns-0.0.1/src/hrns/client/url_policy.py +57 -0
  71. hrns-0.0.1/src/hrns/config/__init__.py +30 -0
  72. hrns-0.0.1/src/hrns/config/mcp.py +288 -0
  73. hrns-0.0.1/src/hrns/config/settings.py +173 -0
  74. hrns-0.0.1/src/hrns/protocol/__init__.py +105 -0
  75. hrns-0.0.1/src/hrns/protocol/errors.py +11 -0
  76. hrns-0.0.1/src/hrns/protocol/extensions.py +161 -0
  77. hrns-0.0.1/src/hrns/protocol/models.py +166 -0
  78. hrns-0.0.1/src/hrns/protocol/py.typed +0 -0
  79. hrns-0.0.1/src/hrns/protocol/transport.py +145 -0
  80. hrns-0.0.1/src/hrns/py.typed +0 -0
  81. hrns-0.0.1/src/hrns/runtime/__init__.py +154 -0
  82. hrns-0.0.1/src/hrns/runtime/_model_usage.py +69 -0
  83. hrns-0.0.1/src/hrns/runtime/_unavailable_tools.py +103 -0
  84. hrns-0.0.1/src/hrns/runtime/_version.py +5 -0
  85. hrns-0.0.1/src/hrns/runtime/_warnings.py +9 -0
  86. hrns-0.0.1/src/hrns/runtime/acp.py +174 -0
  87. hrns-0.0.1/src/hrns/runtime/acp_store.py +398 -0
  88. hrns-0.0.1/src/hrns/runtime/ask_user.py +94 -0
  89. hrns-0.0.1/src/hrns/runtime/capabilities/__init__.py +34 -0
  90. hrns-0.0.1/src/hrns/runtime/capabilities/ask_user/__init__.py +60 -0
  91. hrns-0.0.1/src/hrns/runtime/capabilities/ask_user/_capability.py +36 -0
  92. hrns-0.0.1/src/hrns/runtime/capabilities/ask_user/config.py +22 -0
  93. hrns-0.0.1/src/hrns/runtime/capabilities/coder/__init__.py +60 -0
  94. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_capability.py +91 -0
  95. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_changes.py +208 -0
  96. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_ids.py +19 -0
  97. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_instructions.py +32 -0
  98. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_needs.py +11 -0
  99. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_presentation.py +52 -0
  100. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_search.py +434 -0
  101. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_tools.py +361 -0
  102. hrns-0.0.1/src/hrns/runtime/capabilities/coder/_workspace.py +107 -0
  103. hrns-0.0.1/src/hrns/runtime/capabilities/coder/config.py +41 -0
  104. hrns-0.0.1/src/hrns/runtime/capabilities/mcp/__init__.py +64 -0
  105. hrns-0.0.1/src/hrns/runtime/capabilities/mcp/_capability.py +121 -0
  106. hrns-0.0.1/src/hrns/runtime/capabilities/mcp/_status.py +92 -0
  107. hrns-0.0.1/src/hrns/runtime/capabilities/mcp/config.py +11 -0
  108. hrns-0.0.1/src/hrns/runtime/capabilities/skills/__init__.py +76 -0
  109. hrns-0.0.1/src/hrns/runtime/capabilities/skills/_capability.py +85 -0
  110. hrns-0.0.1/src/hrns/runtime/capabilities/skills/_catalog.py +144 -0
  111. hrns-0.0.1/src/hrns/runtime/capabilities/skills/_invocation.py +73 -0
  112. hrns-0.0.1/src/hrns/runtime/capabilities/skills/_needs.py +7 -0
  113. hrns-0.0.1/src/hrns/runtime/capabilities/skills/config.py +57 -0
  114. hrns-0.0.1/src/hrns/runtime/capabilities/todo/__init__.py +58 -0
  115. hrns-0.0.1/src/hrns/runtime/capabilities/todo/_capability.py +57 -0
  116. hrns-0.0.1/src/hrns/runtime/capabilities/todo/config.py +23 -0
  117. hrns-0.0.1/src/hrns/runtime/cli.py +406 -0
  118. hrns-0.0.1/src/hrns/runtime/command_service.py +209 -0
  119. hrns-0.0.1/src/hrns/runtime/commands.py +170 -0
  120. hrns-0.0.1/src/hrns/runtime/composition.py +526 -0
  121. hrns-0.0.1/src/hrns/runtime/configuration_service.py +164 -0
  122. hrns-0.0.1/src/hrns/runtime/definitions.py +671 -0
  123. hrns-0.0.1/src/hrns/runtime/deps.py +89 -0
  124. hrns-0.0.1/src/hrns/runtime/extensions.py +234 -0
  125. hrns-0.0.1/src/hrns/runtime/host.py +485 -0
  126. hrns-0.0.1/src/hrns/runtime/host_support.py +250 -0
  127. hrns-0.0.1/src/hrns/runtime/local.py +366 -0
  128. hrns-0.0.1/src/hrns/runtime/policy/__init__.py +23 -0
  129. hrns-0.0.1/src/hrns/runtime/policy/binding.py +156 -0
  130. hrns-0.0.1/src/hrns/runtime/policy/catalog.py +439 -0
  131. hrns-0.0.1/src/hrns/runtime/policy/validation.py +468 -0
  132. hrns-0.0.1/src/hrns/runtime/postgres.py +354 -0
  133. hrns-0.0.1/src/hrns/runtime/presentation.py +256 -0
  134. hrns-0.0.1/src/hrns/runtime/registry.py +631 -0
  135. hrns-0.0.1/src/hrns/runtime/resources.py +488 -0
  136. hrns-0.0.1/src/hrns/runtime/session_service.py +446 -0
  137. hrns-0.0.1/src/hrns/runtime/steering.py +59 -0
  138. hrns-0.0.1/src/hrns/runtime/store.py +355 -0
  139. hrns-0.0.1/src/hrns/runtime/todo.py +160 -0
  140. hrns-0.0.1/src/hrns/server/__init__.py +18 -0
  141. hrns-0.0.1/src/hrns/server/_version.py +5 -0
  142. hrns-0.0.1/src/hrns/server/api.py +66 -0
  143. hrns-0.0.1/src/hrns/server/app.py +213 -0
  144. hrns-0.0.1/src/hrns/server/auth.py +64 -0
  145. hrns-0.0.1/src/hrns/server/catalog.py +162 -0
  146. hrns-0.0.1/src/hrns/server/errors.py +123 -0
  147. hrns-0.0.1/src/hrns/server/models.py +67 -0
  148. hrns-0.0.1/src/hrns/server/proxy.py +157 -0
hrns-0.0.1/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .ruff_cache/
6
+ dist/
7
+ build/
8
+ site/
9
+ .cache/
10
+ benchmark-results/
11
+ *.db
12
+ *.db-shm
13
+ *.db-wal
14
+ .env
15
+ .idea
16
+ test.py
17
+ var
hrns-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hrns contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
hrns-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.5
2
+ Name: hrns
3
+ Version: 0.0.1
4
+ Summary: Programmable Pydantic AI agents with an interoperable ACP terminal and hosting
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: platformdirs>=4
9
+ Requires-Dist: pydantic-settings<3,>=2.10
10
+ Requires-Dist: pydantic<3,>=2.12
11
+ Requires-Dist: tomli-w<2,>=1.2
12
+ Provides-Extra: all
13
+ Requires-Dist: agent-client-protocol<0.12,>=0.11; extra == 'all'
14
+ Requires-Dist: fastapi<1,>=0.156; extra == 'all'
15
+ Requires-Dist: fastmcp-slim[client]<5,>=3.3; extra == 'all'
16
+ Requires-Dist: httpx<1,>=0.28; extra == 'all'
17
+ Requires-Dist: keyring>=25; extra == 'all'
18
+ Requires-Dist: packaging>=24; extra == 'all'
19
+ Requires-Dist: psycopg[binary]>=3.2; extra == 'all'
20
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'all'
21
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'all'
22
+ Requires-Dist: pydantic-ai-slim[anthropic]==2.57.0; extra == 'all'
23
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'all'
24
+ Requires-Dist: pydantic-ai-slim[openai]==2.57.0; extra == 'all'
25
+ Requires-Dist: pyyaml<7,>=6; extra == 'all'
26
+ Requires-Dist: starlette<2,>=0.47; extra == 'all'
27
+ Requires-Dist: textual<9,>=8.2; extra == 'all'
28
+ Requires-Dist: uvicorn>=0.35; extra == 'all'
29
+ Requires-Dist: websockets<18,>=15; extra == 'all'
30
+ Provides-Extra: anthropic
31
+ Requires-Dist: keyring>=25; extra == 'anthropic'
32
+ Requires-Dist: packaging>=24; extra == 'anthropic'
33
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'anthropic'
34
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'anthropic'
35
+ Requires-Dist: pydantic-ai-slim[anthropic]==2.57.0; extra == 'anthropic'
36
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'anthropic'
37
+ Requires-Dist: pyyaml<7,>=6; extra == 'anthropic'
38
+ Provides-Extra: client
39
+ Requires-Dist: agent-client-protocol<0.12,>=0.11; extra == 'client'
40
+ Requires-Dist: fastmcp-slim[client]<5,>=3.3; extra == 'client'
41
+ Requires-Dist: httpx<1,>=0.28; extra == 'client'
42
+ Requires-Dist: keyring>=25; extra == 'client'
43
+ Requires-Dist: textual<9,>=8.2; extra == 'client'
44
+ Requires-Dist: websockets<18,>=15; extra == 'client'
45
+ Provides-Extra: openai
46
+ Requires-Dist: keyring>=25; extra == 'openai'
47
+ Requires-Dist: packaging>=24; extra == 'openai'
48
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'openai'
49
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'openai'
50
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'openai'
51
+ Requires-Dist: pydantic-ai-slim[openai]==2.57.0; extra == 'openai'
52
+ Requires-Dist: pyyaml<7,>=6; extra == 'openai'
53
+ Provides-Extra: postgres
54
+ Requires-Dist: keyring>=25; extra == 'postgres'
55
+ Requires-Dist: packaging>=24; extra == 'postgres'
56
+ Requires-Dist: psycopg[binary]>=3.2; extra == 'postgres'
57
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'postgres'
58
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'postgres'
59
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'postgres'
60
+ Requires-Dist: pyyaml<7,>=6; extra == 'postgres'
61
+ Provides-Extra: runtime
62
+ Requires-Dist: keyring>=25; extra == 'runtime'
63
+ Requires-Dist: packaging>=24; extra == 'runtime'
64
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'runtime'
65
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'runtime'
66
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'runtime'
67
+ Requires-Dist: pyyaml<7,>=6; extra == 'runtime'
68
+ Provides-Extra: server
69
+ Requires-Dist: fastapi<1,>=0.156; extra == 'server'
70
+ Requires-Dist: keyring>=25; extra == 'server'
71
+ Requires-Dist: packaging>=24; extra == 'server'
72
+ Requires-Dist: pydantic-ai-harness[acp]==0.57.0; extra == 'server'
73
+ Requires-Dist: pydantic-ai-skills<3,>=2.1; extra == 'server'
74
+ Requires-Dist: pydantic-ai-slim[mcp]==2.57.0; extra == 'server'
75
+ Requires-Dist: pyyaml<7,>=6; extra == 'server'
76
+ Requires-Dist: starlette<2,>=0.47; extra == 'server'
77
+ Requires-Dist: uvicorn>=0.35; extra == 'server'
78
+ Requires-Dist: websockets<18,>=15; extra == 'server'
79
+ Description-Content-Type: text/markdown
80
+
81
+ # Benchmark results
82
+
83
+ Three runs per hrns on a benchmark task using **GPT-6-Luna with medium reasoning**.
84
+
85
+ | hrns | Tests pass | All quality gates pass | Model responses | Tool calls | Total cost | Average/run |
86
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: |
87
+ | Codex | 3/3 | 3/3 | 44 | 56 | $0.03658 | $0.01219 |
88
+ | OpenCode | 3/3 | 2/3 | 43 | 47 | $0.03578 | $0.01193 |
89
+ | **hrns** | **3/3** | **3/3** | **44** | **59** | **$0.03300** | **$0.01100** |
90
+
91
+ All runs pass **130/130 tests**. Quality gates cover Ruff lint, Ruff formatting,
92
+ and Pyrefly type checking.
93
+
94
+ Counts and costs are totals across three runs. Model responses include tool-only
95
+ responses and final answers. Tool calls count underlying attempts, including
96
+ failures; Codex's 41 orchestration calls contain 56 underlying attempts.
97
+ Costs are cache-aware **API equivalents in USD** using common Standard model pricing.
98
+
99
+ Skill loads: **Codex 0/3**, **OpenCode 1/3**, **hrns 3/3**. The loaded skill is
100
+ `incremental-implementation`, with relevant selection and partial adherence.
101
+
102
+ ---
103
+
104
+ # hrns
105
+
106
+ **Define an agent once. Run it in Python, open it in a terminal, or host it remotely.**
107
+
108
+ hrns combines native Pydantic AI capabilities with policy-controlled sessions, an independent ACP terminal, and authenticated remote hosting. Agent behavior stays in ordinary Python; the terminal can also connect to standard ACP agents that do not use this runtime.
109
+
110
+ ## Start developing
111
+
112
+ Requires **Python 3.11+**, macOS or Linux, [uv](https://docs.astral.sh/uv/),
113
+ and [just](https://just.systems/).
114
+
115
+ ```sh
116
+ just install
117
+ just check
118
+ ```
119
+
120
+ The checked-in lockfile pins the tested upstream versions. `just install` also
121
+ installs the [prek](https://prek.j178.dev/) Git hook, which runs `just check` before
122
+ each commit without applying automatic fixes. To install the hook after a manual
123
+ dependency sync, run `uv run prek install`.
124
+
125
+ ## Use a local agent with your model
126
+
127
+ The local developer agent is the default connection mode. Install the provider
128
+ extra and set the API key for the provider you use:
129
+
130
+ ```sh
131
+ uv sync --locked --extra client --extra runtime --extra openai
132
+ export DEEPSEEK_API_KEY='your-key'
133
+ uv run hrns
134
+ ```
135
+
136
+ Press **l** to configure a provider and model, type `/models` in a session, or create
137
+ `hrns.local.toml` in the project:
138
+
139
+ ```toml
140
+ provider = "deepseek"
141
+ model = "deepseek-chat"
142
+ api_key_env = "DEEPSEEK_API_KEY"
143
+ ```
144
+
145
+ `uv run hrns` starts a session in the current directory using that model. The bundled
146
+ `hrns.coder` capability gives it file tools, content search, and a shell in that
147
+ directory: reads are automatic, while writes, edits, and commands ask for approval first.
148
+ `hrns.ask_user` lets the model ask structured multiple-choice questions in the terminal;
149
+ disable it with `[capabilities] ask_user = false` for headless runs. `hrns.todo` gives
150
+ the model a session-scoped plan and shows it in the **Todos** tab of the right drawer.
151
+ Configuration uses pydantic-settings. See
152
+ [local setup](docs/LOCAL.md) for OpenAI-compatible endpoints, local inference, other
153
+ Pydantic AI providers, and headless execution.
154
+
155
+ Useful slash commands include `/connect` (switch or add a target), `/models`
156
+ (configure or select the local model), `/effort` (change reasoning effort live),
157
+ `/plugins` (toggle, configure, or add plugins), `/mcp` (list MCP servers and their
158
+ tools), `/skills` (browse Agent Skills), and `/todo` (open the session's plan).
159
+ Typing `/` shows an inline filtered list. Type `$` in the composer to find a skill and
160
+ insert a `$skill-name` reference, which runs that skill for the message. The older
161
+ `/model` and `/capabilities` names remain aliases.
162
+
163
+ Any independent ACP agent can still be launched explicitly:
164
+
165
+ ```sh
166
+ uv run hrns connect --stdio -- /path/to/agent --acp
167
+ ```
168
+
169
+ See [client usage](docs/CLIENT_API.md) for headless execution, profiles, approvals
170
+ and the bridge.
171
+
172
+ ## Serve agents in your FastAPI app
173
+
174
+ ```python
175
+ from fastapi import FastAPI
176
+ from hrns.runtime import SQLiteSessionStore
177
+ from hrns.server import AgentServer
178
+
179
+ app = FastAPI()
180
+ agents = AgentServer(store=SQLiteSessionStore("./sessions.sqlite3"))
181
+ agents.add_agent(definition)
182
+ agents.mount(app)
183
+ ```
184
+
185
+ `add_agent` binds and validates the definition's resource requirements at registration; pass
186
+ `resources=`, or a `definition.bind(...)` result, when a capability needs host values.
187
+ Install the `server` extra, register your `AgentDefinition` objects, and run the app
188
+ with Uvicorn. Connect using `hrns connect --url http://127.0.0.1:8080 --agent AGENT_ID`.
189
+ PostgreSQL and optional FastAPI authentication dependencies use the same API.
190
+ See [server embedding](docs/SERVER.md) and [the runnable example](examples/fastapi_app.py).
191
+
192
+ ## Layout
193
+
194
+ hrns is one distribution with optional extras. Protocol and local settings
195
+ ship by default; the runtime, terminal, and server dependencies are opt-in.
196
+
197
+ | Module | Extra | Purpose |
198
+ | --- | --- | --- |
199
+ | `hrns.protocol` | base | Versioned extension schemas and transport contracts |
200
+ | `hrns.config` | base | Shared local settings using pydantic-settings |
201
+ | `hrns.runtime` | `runtime` | Native agent definitions, plugin management, sessions, `hrns-host` and `hrns-local` |
202
+ | `hrns.client` | `client` | Textual terminal, scripted ACP runner and stdio bridge |
203
+ | `hrns.server` | `server` | FastAPI agent registration and in-process WebSocket ACP |
204
+
205
+ Install only what you need, for example `pip install 'hrns[client]'`,
206
+ `pip install 'hrns[openai]'`, or `pip install 'hrns[all]'`.
207
+
208
+ The `hrns.client` module does not import Pydantic AI or installed agent
209
+ plugins, and installing `hrns[client]` alone does not install the runtime.
210
+ Local stdio agents run in a separate process. Network agents run inside an existing
211
+ FastAPI application through `AgentServer`, sharing an explicit SQLite or PostgreSQL store.
212
+
213
+ ## Design essentials
214
+
215
+ - **Upstream ACP execution:** `PydanticAIACPAgent` owns prompts, streaming, approvals, cancellation, history, and transcript replay.
216
+ - **Native composition:** managed bindings contribute their complete Pydantic AI behavior—tools, instructions, hooks and settings—and are selected when a session is composed.
217
+ - **Live model and effort:** both use standard ACP configuration options and apply from the next request.
218
+ - **Host-owned state:** sessions pin their principal/deployment scope, retain history and metadata, and never silently retry an uncertain prompt.
219
+ - **Explicit resources:** workspace and provider bindings belong to the host. A local workspace is a path, not a sandbox.
220
+ - **Standard ACP first:** generic streaming content, tools and approvals work without project-specific extensions.
221
+
222
+ ## Checks and distribution builds
223
+
224
+ ```sh
225
+ just check
226
+ just lint
227
+ just build
228
+ just fix
229
+ ```
230
+
231
+ `just check` runs the checks and builds the package. `just lint` runs formatting,
232
+ lint, and type checks; `just build` builds the package. `just fix` applies automatic
233
+ formatting and lint fixes. CI exercises the same non-mutating checks on
234
+ macOS/Linux and Python 3.11–3.13. A wheel and source distribution are written to `dist/`; optional dependencies are declared as extras.
235
+
236
+ External provider, sandbox and durability integrations need their upstream extras and credentials. See the coverage matrix for managed, locally verified and deployment-only distinctions.
237
+
238
+ ## Releasing
239
+
240
+ The version comes from the git tag via hatch-vcs, so there is no version string to
241
+ edit. Publishing runs on release: create a GitHub release and
242
+ `.github/workflows/publish.yml` builds the distribution, runs `just check`, verifies
243
+ the tag, and uploads to PyPI.
244
+
245
+ ```sh
246
+ git tag 0.1.0
247
+ git push origin 0.1.0
248
+ gh release create 0.1.0 --generate-notes
249
+ ```
250
+
251
+ The tag must match the version hatch-vcs derives, so `0.1.0` publishes `0.1.0`. A
252
+ mismatched tag fails the build instead of uploading an unintended version, and a
253
+ version that already exists on PyPI is rejected.
254
+
255
+ Uploads use PyPI Trusted Publishing, so no API token is stored in the repository.
256
+ Before the first release, configure a publisher on PyPI for the `hrns` project with
257
+ this repository's owner and name, workflow `publish.yml`, and environment `pypi`.
258
+ Because `hrns` does not exist on PyPI yet, use the pending publisher form.
259
+
260
+ ## License
261
+
262
+ MIT. See [LICENSE](LICENSE).
hrns-0.0.1/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # Benchmark results
2
+
3
+ Three runs per hrns on a benchmark task using **GPT-6-Luna with medium reasoning**.
4
+
5
+ | hrns | Tests pass | All quality gates pass | Model responses | Tool calls | Total cost | Average/run |
6
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: |
7
+ | Codex | 3/3 | 3/3 | 44 | 56 | $0.03658 | $0.01219 |
8
+ | OpenCode | 3/3 | 2/3 | 43 | 47 | $0.03578 | $0.01193 |
9
+ | **hrns** | **3/3** | **3/3** | **44** | **59** | **$0.03300** | **$0.01100** |
10
+
11
+ All runs pass **130/130 tests**. Quality gates cover Ruff lint, Ruff formatting,
12
+ and Pyrefly type checking.
13
+
14
+ Counts and costs are totals across three runs. Model responses include tool-only
15
+ responses and final answers. Tool calls count underlying attempts, including
16
+ failures; Codex's 41 orchestration calls contain 56 underlying attempts.
17
+ Costs are cache-aware **API equivalents in USD** using common Standard model pricing.
18
+
19
+ Skill loads: **Codex 0/3**, **OpenCode 1/3**, **hrns 3/3**. The loaded skill is
20
+ `incremental-implementation`, with relevant selection and partial adherence.
21
+
22
+ ---
23
+
24
+ # hrns
25
+
26
+ **Define an agent once. Run it in Python, open it in a terminal, or host it remotely.**
27
+
28
+ hrns combines native Pydantic AI capabilities with policy-controlled sessions, an independent ACP terminal, and authenticated remote hosting. Agent behavior stays in ordinary Python; the terminal can also connect to standard ACP agents that do not use this runtime.
29
+
30
+ ## Start developing
31
+
32
+ Requires **Python 3.11+**, macOS or Linux, [uv](https://docs.astral.sh/uv/),
33
+ and [just](https://just.systems/).
34
+
35
+ ```sh
36
+ just install
37
+ just check
38
+ ```
39
+
40
+ The checked-in lockfile pins the tested upstream versions. `just install` also
41
+ installs the [prek](https://prek.j178.dev/) Git hook, which runs `just check` before
42
+ each commit without applying automatic fixes. To install the hook after a manual
43
+ dependency sync, run `uv run prek install`.
44
+
45
+ ## Use a local agent with your model
46
+
47
+ The local developer agent is the default connection mode. Install the provider
48
+ extra and set the API key for the provider you use:
49
+
50
+ ```sh
51
+ uv sync --locked --extra client --extra runtime --extra openai
52
+ export DEEPSEEK_API_KEY='your-key'
53
+ uv run hrns
54
+ ```
55
+
56
+ Press **l** to configure a provider and model, type `/models` in a session, or create
57
+ `hrns.local.toml` in the project:
58
+
59
+ ```toml
60
+ provider = "deepseek"
61
+ model = "deepseek-chat"
62
+ api_key_env = "DEEPSEEK_API_KEY"
63
+ ```
64
+
65
+ `uv run hrns` starts a session in the current directory using that model. The bundled
66
+ `hrns.coder` capability gives it file tools, content search, and a shell in that
67
+ directory: reads are automatic, while writes, edits, and commands ask for approval first.
68
+ `hrns.ask_user` lets the model ask structured multiple-choice questions in the terminal;
69
+ disable it with `[capabilities] ask_user = false` for headless runs. `hrns.todo` gives
70
+ the model a session-scoped plan and shows it in the **Todos** tab of the right drawer.
71
+ Configuration uses pydantic-settings. See
72
+ [local setup](docs/LOCAL.md) for OpenAI-compatible endpoints, local inference, other
73
+ Pydantic AI providers, and headless execution.
74
+
75
+ Useful slash commands include `/connect` (switch or add a target), `/models`
76
+ (configure or select the local model), `/effort` (change reasoning effort live),
77
+ `/plugins` (toggle, configure, or add plugins), `/mcp` (list MCP servers and their
78
+ tools), `/skills` (browse Agent Skills), and `/todo` (open the session's plan).
79
+ Typing `/` shows an inline filtered list. Type `$` in the composer to find a skill and
80
+ insert a `$skill-name` reference, which runs that skill for the message. The older
81
+ `/model` and `/capabilities` names remain aliases.
82
+
83
+ Any independent ACP agent can still be launched explicitly:
84
+
85
+ ```sh
86
+ uv run hrns connect --stdio -- /path/to/agent --acp
87
+ ```
88
+
89
+ See [client usage](docs/CLIENT_API.md) for headless execution, profiles, approvals
90
+ and the bridge.
91
+
92
+ ## Serve agents in your FastAPI app
93
+
94
+ ```python
95
+ from fastapi import FastAPI
96
+ from hrns.runtime import SQLiteSessionStore
97
+ from hrns.server import AgentServer
98
+
99
+ app = FastAPI()
100
+ agents = AgentServer(store=SQLiteSessionStore("./sessions.sqlite3"))
101
+ agents.add_agent(definition)
102
+ agents.mount(app)
103
+ ```
104
+
105
+ `add_agent` binds and validates the definition's resource requirements at registration; pass
106
+ `resources=`, or a `definition.bind(...)` result, when a capability needs host values.
107
+ Install the `server` extra, register your `AgentDefinition` objects, and run the app
108
+ with Uvicorn. Connect using `hrns connect --url http://127.0.0.1:8080 --agent AGENT_ID`.
109
+ PostgreSQL and optional FastAPI authentication dependencies use the same API.
110
+ See [server embedding](docs/SERVER.md) and [the runnable example](examples/fastapi_app.py).
111
+
112
+ ## Layout
113
+
114
+ hrns is one distribution with optional extras. Protocol and local settings
115
+ ship by default; the runtime, terminal, and server dependencies are opt-in.
116
+
117
+ | Module | Extra | Purpose |
118
+ | --- | --- | --- |
119
+ | `hrns.protocol` | base | Versioned extension schemas and transport contracts |
120
+ | `hrns.config` | base | Shared local settings using pydantic-settings |
121
+ | `hrns.runtime` | `runtime` | Native agent definitions, plugin management, sessions, `hrns-host` and `hrns-local` |
122
+ | `hrns.client` | `client` | Textual terminal, scripted ACP runner and stdio bridge |
123
+ | `hrns.server` | `server` | FastAPI agent registration and in-process WebSocket ACP |
124
+
125
+ Install only what you need, for example `pip install 'hrns[client]'`,
126
+ `pip install 'hrns[openai]'`, or `pip install 'hrns[all]'`.
127
+
128
+ The `hrns.client` module does not import Pydantic AI or installed agent
129
+ plugins, and installing `hrns[client]` alone does not install the runtime.
130
+ Local stdio agents run in a separate process. Network agents run inside an existing
131
+ FastAPI application through `AgentServer`, sharing an explicit SQLite or PostgreSQL store.
132
+
133
+ ## Design essentials
134
+
135
+ - **Upstream ACP execution:** `PydanticAIACPAgent` owns prompts, streaming, approvals, cancellation, history, and transcript replay.
136
+ - **Native composition:** managed bindings contribute their complete Pydantic AI behavior—tools, instructions, hooks and settings—and are selected when a session is composed.
137
+ - **Live model and effort:** both use standard ACP configuration options and apply from the next request.
138
+ - **Host-owned state:** sessions pin their principal/deployment scope, retain history and metadata, and never silently retry an uncertain prompt.
139
+ - **Explicit resources:** workspace and provider bindings belong to the host. A local workspace is a path, not a sandbox.
140
+ - **Standard ACP first:** generic streaming content, tools and approvals work without project-specific extensions.
141
+
142
+ ## Checks and distribution builds
143
+
144
+ ```sh
145
+ just check
146
+ just lint
147
+ just build
148
+ just fix
149
+ ```
150
+
151
+ `just check` runs the checks and builds the package. `just lint` runs formatting,
152
+ lint, and type checks; `just build` builds the package. `just fix` applies automatic
153
+ formatting and lint fixes. CI exercises the same non-mutating checks on
154
+ macOS/Linux and Python 3.11–3.13. A wheel and source distribution are written to `dist/`; optional dependencies are declared as extras.
155
+
156
+ External provider, sandbox and durability integrations need their upstream extras and credentials. See the coverage matrix for managed, locally verified and deployment-only distinctions.
157
+
158
+ ## Releasing
159
+
160
+ The version comes from the git tag via hatch-vcs, so there is no version string to
161
+ edit. Publishing runs on release: create a GitHub release and
162
+ `.github/workflows/publish.yml` builds the distribution, runs `just check`, verifies
163
+ the tag, and uploads to PyPI.
164
+
165
+ ```sh
166
+ git tag 0.1.0
167
+ git push origin 0.1.0
168
+ gh release create 0.1.0 --generate-notes
169
+ ```
170
+
171
+ The tag must match the version hatch-vcs derives, so `0.1.0` publishes `0.1.0`. A
172
+ mismatched tag fails the build instead of uploading an unintended version, and a
173
+ version that already exists on PyPI is rejected.
174
+
175
+ Uploads use PyPI Trusted Publishing, so no API token is stored in the repository.
176
+ Before the first release, configure a publisher on PyPI for the `hrns` project with
177
+ this repository's owner and name, workflow `publish.yml`, and environment `pypi`.
178
+ Because `hrns` does not exist on PyPI yet, use the pending publisher form.
179
+
180
+ ## License
181
+
182
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,103 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hrns"
7
+ dynamic = ["version"]
8
+ description = "Programmable Pydantic AI agents with an interoperable ACP terminal and hosting"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ dependencies = [
13
+ "pydantic>=2.12,<3",
14
+ "pydantic-settings>=2.10,<3",
15
+ "platformdirs>=4",
16
+ "tomli-w>=1.2,<2",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ client = [
21
+ "agent-client-protocol>=0.11,<0.12",
22
+ "textual>=8.2,<9",
23
+ "httpx>=0.28,<1",
24
+ "websockets>=15,<18",
25
+ "keyring>=25",
26
+ "fastmcp-slim[client]>=3.3,<5",
27
+ ]
28
+ runtime = [
29
+ "pydantic-ai-slim[mcp]==2.57.0",
30
+ "pydantic-ai-harness[acp]==0.57.0",
31
+ "PyYAML>=6,<7",
32
+ "packaging>=24",
33
+ "pydantic-ai-skills>=2.1,<3",
34
+ "keyring>=25",
35
+ ]
36
+ server = [
37
+ "hrns[runtime]",
38
+ "fastapi>=0.156,<1",
39
+ "starlette>=0.47,<2",
40
+ "uvicorn>=0.35",
41
+ "websockets>=15,<18",
42
+ ]
43
+ openai = [
44
+ "hrns[runtime]",
45
+ "pydantic-ai-slim[openai]==2.57.0",
46
+ ]
47
+ anthropic = [
48
+ "hrns[runtime]",
49
+ "pydantic-ai-slim[anthropic]==2.57.0",
50
+ ]
51
+ postgres = [
52
+ "hrns[runtime]",
53
+ "psycopg[binary]>=3.2",
54
+ ]
55
+ all = [
56
+ "hrns[client,runtime,server,openai,anthropic,postgres]",
57
+ ]
58
+
59
+ [project.scripts]
60
+ hrns = "hrns.client.cli:main"
61
+ hrns-host = "hrns.runtime.cli:main"
62
+ hrns-local = "hrns.runtime.local:main"
63
+
64
+ [dependency-groups]
65
+ dev = [
66
+ "ruff>=0.11",
67
+ "build>=1.2",
68
+ "httpx>=0.28",
69
+ "pyrefly>=1.4.0",
70
+ "types-pyyaml>=6",
71
+ "prek>=0.5.7",
72
+ ]
73
+ docs = [
74
+ "mkdocstrings-python>=2.0.10",
75
+ "zensical>=0.0.67,<0.1",
76
+ ]
77
+
78
+ [tool.hatch.version]
79
+ source = "vcs"
80
+ fallback-version = "0.0.1"
81
+
82
+ [tool.hatch.build.targets.wheel]
83
+ packages = ["src/hrns"]
84
+
85
+ [tool.hatch.build.targets.sdist]
86
+ include = ["/src", "/README.md", "/LICENSE"]
87
+
88
+ [tool.ruff]
89
+ target-version = "py311"
90
+ line-length = 100
91
+ src = ["src"]
92
+
93
+ [tool.ruff.lint]
94
+ select = ["E4", "E7", "E9", "F", "I"]
95
+
96
+ [tool.ruff.lint.isort]
97
+ known-first-party = ["hrns"]
98
+
99
+ [tool.pyrefly]
100
+ project-includes = [
101
+ "**/*.py*",
102
+ "**/*.ipynb",
103
+ ]
@@ -0,0 +1,13 @@
1
+ """hrns: programmable Pydantic AI agents with an ACP terminal and hosting.
2
+
3
+ The distribution exposes independent subpackages:
4
+
5
+ - ``hrns.protocol``: versioned contracts and transport framing.
6
+ - ``hrns.config``: shared local settings.
7
+ - ``hrns.runtime``: native agent definitions, sessions, and ACP hosting.
8
+ - ``hrns.client``: Textual terminal, headless runner, and stdio bridge.
9
+ - ``hrns.server``: authenticated deployment catalog and worker hosting.
10
+
11
+ Importing ``hrns`` does not import any subpackage, so the client and server
12
+ keep their independent dependency boundaries.
13
+ """