rocannon 0.1.0__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.
- rocannon-0.1.0/PKG-INFO +213 -0
- rocannon-0.1.0/README.md +170 -0
- rocannon-0.1.0/pyproject.toml +155 -0
- rocannon-0.1.0/src/rocannon/__init__.py +0 -0
- rocannon-0.1.0/src/rocannon/ansible.py +500 -0
- rocannon-0.1.0/src/rocannon/cli.py +1136 -0
- rocannon-0.1.0/src/rocannon/config.py +68 -0
- rocannon-0.1.0/src/rocannon/correlation.py +50 -0
- rocannon-0.1.0/src/rocannon/executor.py +218 -0
- rocannon-0.1.0/src/rocannon/history.py +57 -0
- rocannon-0.1.0/src/rocannon/inventory.py +39 -0
- rocannon-0.1.0/src/rocannon/playbook.py +328 -0
- rocannon-0.1.0/src/rocannon/profiles.py +175 -0
- rocannon-0.1.0/src/rocannon/py.typed +0 -0
- rocannon-0.1.0/src/rocannon/redaction.py +57 -0
- rocannon-0.1.0/src/rocannon/repl.py +470 -0
- rocannon-0.1.0/src/rocannon/schema.py +193 -0
- rocannon-0.1.0/src/rocannon/server.py +651 -0
rocannon-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rocannon
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Every Ansible module as a typed MCP tool
|
|
5
|
+
Keywords: ansible,mcp,model-context-protocol,automation,ibm-z,zos
|
|
6
|
+
Author: Adam Munawar Rahman
|
|
7
|
+
Author-email: Adam Munawar Rahman <msrahmanadam@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: System :: Systems Administration
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: fastmcp>=3.4.2
|
|
20
|
+
Requires-Dist: prompt-toolkit>=3.0.52
|
|
21
|
+
Requires-Dist: typer>=0.26.7
|
|
22
|
+
Requires-Dist: pydantic>=2.13.4
|
|
23
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
24
|
+
Requires-Dist: litellm>=1.89.0 ; extra == 'ai'
|
|
25
|
+
Requires-Dist: ansible-core>=2.21.0 ; extra == 'all'
|
|
26
|
+
Requires-Dist: ansible-runner>=2.4.3 ; extra == 'all'
|
|
27
|
+
Requires-Dist: litellm>=1.89.0 ; extra == 'all'
|
|
28
|
+
Requires-Dist: opentelemetry-sdk>=1.42.1 ; extra == 'all'
|
|
29
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.42.1 ; extra == 'all'
|
|
30
|
+
Requires-Dist: ansible-core>=2.21.0 ; extra == 'ansible'
|
|
31
|
+
Requires-Dist: ansible-runner>=2.4.3 ; extra == 'ansible'
|
|
32
|
+
Requires-Dist: opentelemetry-sdk>=1.42.1 ; extra == 'otel'
|
|
33
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.42.1 ; extra == 'otel'
|
|
34
|
+
Requires-Python: >=3.12
|
|
35
|
+
Project-URL: Homepage, https://github.com/msradam/rocannon
|
|
36
|
+
Project-URL: Repository, https://github.com/msradam/rocannon
|
|
37
|
+
Project-URL: Issues, https://github.com/msradam/rocannon/issues
|
|
38
|
+
Provides-Extra: ai
|
|
39
|
+
Provides-Extra: all
|
|
40
|
+
Provides-Extra: ansible
|
|
41
|
+
Provides-Extra: otel
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
<h1 align="center">Rocannon</h1>
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
<img src="https://raw.githubusercontent.com/msradam/rocannon/main/docs/assets/gryphon.svg" alt="" width="120">
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
Rocannon is an MCP server that registers every installed Ansible module as a
|
|
51
|
+
typed tool. It reads `ansible-doc -j` for each module at startup and builds a
|
|
52
|
+
Pydantic-validated function signature, then exposes the result over the MCP
|
|
53
|
+
protocol (stdio or HTTP). Any MCP client (Claude Code, Cursor, mcphost,
|
|
54
|
+
custom agents) calls the same tools an operator would call from a REPL.
|
|
55
|
+
|
|
56
|
+
Each registered tool carries the module's own `ansible-doc` metadata: a JSON
|
|
57
|
+
output schema for structured results, and MCP safety hints derived from the
|
|
58
|
+
module's attributes (read-only for fact modules, destructive and open-world for
|
|
59
|
+
`command`, `shell`, `script`, and `raw`).
|
|
60
|
+
|
|
61
|
+
Every module is also a top-level CLI subcommand:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
rocannon ansible.builtin.command --target h1 --cmd 'uptime'
|
|
65
|
+
rocannon ansible.builtin.copy --target h1 --src /etc/hosts --dest /tmp/h
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Append `--record path/to/runbook.yml` to any invocation and Rocannon writes
|
|
69
|
+
each call as a new play in a real Ansible playbook. The resulting file runs
|
|
70
|
+
directly under `ansible-playbook -i <inv> path/to/runbook.yml`.
|
|
71
|
+
|
|
72
|
+
Add `--check` to preview a change without applying it (Ansible check mode) and
|
|
73
|
+
`--diff` to see what would change. Each is offered per module according to its
|
|
74
|
+
declared check-mode support, both on the CLI and as a parameter on the matching
|
|
75
|
+
MCP tool. `rocannon playbook run <name> --check` previews an entire saved runbook.
|
|
76
|
+
|
|
77
|
+
Sessions driven via the MCP server save the same way: as Ansible playbooks
|
|
78
|
+
under `.rocannon/playbooks/`. Rocannon also loads them back on next startup
|
|
79
|
+
as MCP prompts.
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
## Install
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install 'rocannon[ansible]'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`ansible-doc` and `ansible-runner` must be on PATH. `rocannon doctor` reports
|
|
90
|
+
anything missing.
|
|
91
|
+
|
|
92
|
+
## Quickstart
|
|
93
|
+
|
|
94
|
+
The quickstart profile targets `localhost` with `ansible_connection=local`.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cd examples/quickstart
|
|
98
|
+
rocannon mcp doctor --profile profile.yml # list registered tools
|
|
99
|
+
rocannon repl --profile profile.yml # operator shell
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Inside the REPL:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
rocannon> .target localhost
|
|
106
|
+
rocannon> ping
|
|
107
|
+
rocannon> command cmd="uptime"
|
|
108
|
+
rocannon> .save my_session
|
|
109
|
+
rocannon> .exit
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`.save` writes `.rocannon/playbooks/my_session.yml` as a standard Ansible
|
|
113
|
+
playbook. Run it directly with `ansible-playbook -i hosts my_session.yml`, or
|
|
114
|
+
let Rocannon load it back as an MCP prompt next time the server starts.
|
|
115
|
+
|
|
116
|
+
## CLI
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
rocannon <fqcn> invoke a module: rocannon ansible.builtin.copy ...
|
|
120
|
+
optional --record FILE appends each call to a playbook
|
|
121
|
+
rocannon mcp serve start the MCP server (stdio or http)
|
|
122
|
+
rocannon mcp doctor list registered tools, resources, prompts
|
|
123
|
+
rocannon repl interactive shell on the same MCP server
|
|
124
|
+
rocannon run legacy ad-hoc form (module FQCN + -a key=value)
|
|
125
|
+
rocannon doctor system health (binaries, env, inventory)
|
|
126
|
+
rocannon doc <module> print parsed schema for a module
|
|
127
|
+
rocannon search <q> find modules by name or description
|
|
128
|
+
rocannon ls list hosts/groups/modules from a profile
|
|
129
|
+
rocannon playbook list/show/run saved playbooks
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Per-module help (typed flags, defaults, descriptions from `ansible-doc`):
|
|
133
|
+
`rocannon ansible.builtin.copy --help`. Modules that support check mode also
|
|
134
|
+
accept `--check` and `--diff`.
|
|
135
|
+
|
|
136
|
+
## Profiles
|
|
137
|
+
|
|
138
|
+
A profile is a YAML file declaring inventory + modules:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
inventories:
|
|
142
|
+
- ./hosts
|
|
143
|
+
modules:
|
|
144
|
+
- ansible.builtin
|
|
145
|
+
- ibm.ibm_zos_core
|
|
146
|
+
ansible_cfg: ./ansible.cfg # optional
|
|
147
|
+
vault_password_file: ~/.vault_pass # optional
|
|
148
|
+
extra_envvars: # optional
|
|
149
|
+
ZOAU_HOME: /usr/lpp/IBM/zoautil
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`modules` accepts a specific module (`ansible.builtin.copy`), a collection
|
|
153
|
+
(`ansible.builtin`), or a namespace (`community`).
|
|
154
|
+
|
|
155
|
+
Multiple profiles can live under `.rocannon/profiles/`:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
.rocannon/profiles/
|
|
159
|
+
├── box1.yml
|
|
160
|
+
├── box2.yml
|
|
161
|
+
└── default.yml -> box1.yml
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
rocannon mcp serve # uses default.yml
|
|
166
|
+
rocannon mcp serve --profile box2
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The active profile can be switched at runtime via three MCP tools:
|
|
170
|
+
`rocannon_list_profiles`, `rocannon_current_profile`, `rocannon_use_profile`.
|
|
171
|
+
The tool surface is the union of every profile's modules; a call to a module
|
|
172
|
+
that isn't in the active profile returns a structured error pointing at
|
|
173
|
+
`rocannon_use_profile`.
|
|
174
|
+
|
|
175
|
+
## MCP clients
|
|
176
|
+
|
|
177
|
+
A working `.mcp.json` ships at the repo root. Per-client snippets are in
|
|
178
|
+
[`examples/clients/`](examples/clients/).
|
|
179
|
+
|
|
180
|
+
| Client | Config location |
|
|
181
|
+
|---|---|
|
|
182
|
+
| Claude Code | `.mcp.json` at project root, or `claude mcp add` |
|
|
183
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
184
|
+
| Cursor | `.cursor/mcp.json` or `~/.cursor/mcp.json` |
|
|
185
|
+
| mcphost | `~/.mcphost.yml` or `--config <path>` |
|
|
186
|
+
| IBM Bob | `.bob/mcp.json` or `~/.bob/mcp_settings.json` |
|
|
187
|
+
|
|
188
|
+
All share the standard `mcpServers` envelope pointing at
|
|
189
|
+
`rocannon mcp serve --profile <your-profile.yml>`.
|
|
190
|
+
|
|
191
|
+
## Development
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
git clone https://github.com/msradam/rocannon.git
|
|
195
|
+
cd rocannon
|
|
196
|
+
uv sync
|
|
197
|
+
./tests/check.sh # ruff format + lint + mypy + pytest
|
|
198
|
+
uv run pytest -m integration # opt-in: spins up a real UBI9 container
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
See [`ARCHITECTURE.md`](ARCHITECTURE.md) for how the pieces fit together.
|
|
202
|
+
|
|
203
|
+
Rocannon is developed with AI assistance.
|
|
204
|
+
|
|
205
|
+
## The name
|
|
206
|
+
|
|
207
|
+
Ursula K. Le Guin coined the word "ansible" in her 1966 novel *Rocannon's
|
|
208
|
+
World*. The gryphon is a nod to the Windsteeds that Rocannon and his
|
|
209
|
+
companions ride.
|
|
210
|
+
|
|
211
|
+
## Credits
|
|
212
|
+
|
|
213
|
+
- Gryphon icon: [Gryphon by Aleksei Kovalenko from Noun Project](https://thenounproject.com/icon/gryphon-7096619/) (CC BY 3.0).
|
rocannon-0.1.0/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<h1 align="center">Rocannon</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/msradam/rocannon/main/docs/assets/gryphon.svg" alt="" width="120">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Rocannon is an MCP server that registers every installed Ansible module as a
|
|
8
|
+
typed tool. It reads `ansible-doc -j` for each module at startup and builds a
|
|
9
|
+
Pydantic-validated function signature, then exposes the result over the MCP
|
|
10
|
+
protocol (stdio or HTTP). Any MCP client (Claude Code, Cursor, mcphost,
|
|
11
|
+
custom agents) calls the same tools an operator would call from a REPL.
|
|
12
|
+
|
|
13
|
+
Each registered tool carries the module's own `ansible-doc` metadata: a JSON
|
|
14
|
+
output schema for structured results, and MCP safety hints derived from the
|
|
15
|
+
module's attributes (read-only for fact modules, destructive and open-world for
|
|
16
|
+
`command`, `shell`, `script`, and `raw`).
|
|
17
|
+
|
|
18
|
+
Every module is also a top-level CLI subcommand:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
rocannon ansible.builtin.command --target h1 --cmd 'uptime'
|
|
22
|
+
rocannon ansible.builtin.copy --target h1 --src /etc/hosts --dest /tmp/h
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Append `--record path/to/runbook.yml` to any invocation and Rocannon writes
|
|
26
|
+
each call as a new play in a real Ansible playbook. The resulting file runs
|
|
27
|
+
directly under `ansible-playbook -i <inv> path/to/runbook.yml`.
|
|
28
|
+
|
|
29
|
+
Add `--check` to preview a change without applying it (Ansible check mode) and
|
|
30
|
+
`--diff` to see what would change. Each is offered per module according to its
|
|
31
|
+
declared check-mode support, both on the CLI and as a parameter on the matching
|
|
32
|
+
MCP tool. `rocannon playbook run <name> --check` previews an entire saved runbook.
|
|
33
|
+
|
|
34
|
+
Sessions driven via the MCP server save the same way: as Ansible playbooks
|
|
35
|
+
under `.rocannon/playbooks/`. Rocannon also loads them back on next startup
|
|
36
|
+
as MCP prompts.
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install 'rocannon[ansible]'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`ansible-doc` and `ansible-runner` must be on PATH. `rocannon doctor` reports
|
|
47
|
+
anything missing.
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
The quickstart profile targets `localhost` with `ansible_connection=local`.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd examples/quickstart
|
|
55
|
+
rocannon mcp doctor --profile profile.yml # list registered tools
|
|
56
|
+
rocannon repl --profile profile.yml # operator shell
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Inside the REPL:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
rocannon> .target localhost
|
|
63
|
+
rocannon> ping
|
|
64
|
+
rocannon> command cmd="uptime"
|
|
65
|
+
rocannon> .save my_session
|
|
66
|
+
rocannon> .exit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`.save` writes `.rocannon/playbooks/my_session.yml` as a standard Ansible
|
|
70
|
+
playbook. Run it directly with `ansible-playbook -i hosts my_session.yml`, or
|
|
71
|
+
let Rocannon load it back as an MCP prompt next time the server starts.
|
|
72
|
+
|
|
73
|
+
## CLI
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
rocannon <fqcn> invoke a module: rocannon ansible.builtin.copy ...
|
|
77
|
+
optional --record FILE appends each call to a playbook
|
|
78
|
+
rocannon mcp serve start the MCP server (stdio or http)
|
|
79
|
+
rocannon mcp doctor list registered tools, resources, prompts
|
|
80
|
+
rocannon repl interactive shell on the same MCP server
|
|
81
|
+
rocannon run legacy ad-hoc form (module FQCN + -a key=value)
|
|
82
|
+
rocannon doctor system health (binaries, env, inventory)
|
|
83
|
+
rocannon doc <module> print parsed schema for a module
|
|
84
|
+
rocannon search <q> find modules by name or description
|
|
85
|
+
rocannon ls list hosts/groups/modules from a profile
|
|
86
|
+
rocannon playbook list/show/run saved playbooks
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Per-module help (typed flags, defaults, descriptions from `ansible-doc`):
|
|
90
|
+
`rocannon ansible.builtin.copy --help`. Modules that support check mode also
|
|
91
|
+
accept `--check` and `--diff`.
|
|
92
|
+
|
|
93
|
+
## Profiles
|
|
94
|
+
|
|
95
|
+
A profile is a YAML file declaring inventory + modules:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
inventories:
|
|
99
|
+
- ./hosts
|
|
100
|
+
modules:
|
|
101
|
+
- ansible.builtin
|
|
102
|
+
- ibm.ibm_zos_core
|
|
103
|
+
ansible_cfg: ./ansible.cfg # optional
|
|
104
|
+
vault_password_file: ~/.vault_pass # optional
|
|
105
|
+
extra_envvars: # optional
|
|
106
|
+
ZOAU_HOME: /usr/lpp/IBM/zoautil
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`modules` accepts a specific module (`ansible.builtin.copy`), a collection
|
|
110
|
+
(`ansible.builtin`), or a namespace (`community`).
|
|
111
|
+
|
|
112
|
+
Multiple profiles can live under `.rocannon/profiles/`:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
.rocannon/profiles/
|
|
116
|
+
├── box1.yml
|
|
117
|
+
├── box2.yml
|
|
118
|
+
└── default.yml -> box1.yml
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
rocannon mcp serve # uses default.yml
|
|
123
|
+
rocannon mcp serve --profile box2
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The active profile can be switched at runtime via three MCP tools:
|
|
127
|
+
`rocannon_list_profiles`, `rocannon_current_profile`, `rocannon_use_profile`.
|
|
128
|
+
The tool surface is the union of every profile's modules; a call to a module
|
|
129
|
+
that isn't in the active profile returns a structured error pointing at
|
|
130
|
+
`rocannon_use_profile`.
|
|
131
|
+
|
|
132
|
+
## MCP clients
|
|
133
|
+
|
|
134
|
+
A working `.mcp.json` ships at the repo root. Per-client snippets are in
|
|
135
|
+
[`examples/clients/`](examples/clients/).
|
|
136
|
+
|
|
137
|
+
| Client | Config location |
|
|
138
|
+
|---|---|
|
|
139
|
+
| Claude Code | `.mcp.json` at project root, or `claude mcp add` |
|
|
140
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
141
|
+
| Cursor | `.cursor/mcp.json` or `~/.cursor/mcp.json` |
|
|
142
|
+
| mcphost | `~/.mcphost.yml` or `--config <path>` |
|
|
143
|
+
| IBM Bob | `.bob/mcp.json` or `~/.bob/mcp_settings.json` |
|
|
144
|
+
|
|
145
|
+
All share the standard `mcpServers` envelope pointing at
|
|
146
|
+
`rocannon mcp serve --profile <your-profile.yml>`.
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
git clone https://github.com/msradam/rocannon.git
|
|
152
|
+
cd rocannon
|
|
153
|
+
uv sync
|
|
154
|
+
./tests/check.sh # ruff format + lint + mypy + pytest
|
|
155
|
+
uv run pytest -m integration # opt-in: spins up a real UBI9 container
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See [`ARCHITECTURE.md`](ARCHITECTURE.md) for how the pieces fit together.
|
|
159
|
+
|
|
160
|
+
Rocannon is developed with AI assistance.
|
|
161
|
+
|
|
162
|
+
## The name
|
|
163
|
+
|
|
164
|
+
Ursula K. Le Guin coined the word "ansible" in her 1966 novel *Rocannon's
|
|
165
|
+
World*. The gryphon is a nod to the Windsteeds that Rocannon and his
|
|
166
|
+
companions ride.
|
|
167
|
+
|
|
168
|
+
## Credits
|
|
169
|
+
|
|
170
|
+
- Gryphon icon: [Gryphon by Aleksei Kovalenko from Noun Project](https://thenounproject.com/icon/gryphon-7096619/) (CC BY 3.0).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rocannon"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Every Ansible module as a typed MCP tool"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Adam Munawar Rahman", email = "msrahmanadam@gmail.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
keywords = ["ansible", "mcp", "model-context-protocol", "automation", "ibm-z", "zos"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Environment :: Console",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Intended Audience :: System Administrators",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: System :: Systems Administration",
|
|
21
|
+
"Topic :: Utilities",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
# Core framework only; Ansible is opt-in via the `ansible` extra.
|
|
26
|
+
dependencies = [
|
|
27
|
+
"fastmcp>=3.4.2",
|
|
28
|
+
"prompt_toolkit>=3.0.52",
|
|
29
|
+
"typer>=0.26.7",
|
|
30
|
+
"pydantic>=2.13.4",
|
|
31
|
+
"pyyaml>=6.0.3",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
# `pip install 'rocannon[ansible]'` pulls in ansible-core + ansible-runner.
|
|
36
|
+
ansible = [
|
|
37
|
+
"ansible-core>=2.21.0",
|
|
38
|
+
"ansible-runner>=2.4.3",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# --- AI ---
|
|
42
|
+
# `pip install 'rocannon[ai]'` enables `.ai` mode in the REPL. Backend is
|
|
43
|
+
# picked per-call via ROCANNON_AI_MODEL (e.g. "anthropic/claude-sonnet-4-5",
|
|
44
|
+
# "openai/gpt-4o", "ollama/llama3.1", "watsonx/<model>"). LiteLLM owns the
|
|
45
|
+
# provider matrix; rocannon stays unopinionated about it.
|
|
46
|
+
ai = [
|
|
47
|
+
"litellm>=1.89.0",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
# --- Observability ---
|
|
51
|
+
# `pip install 'rocannon[otel]'`; run under `opentelemetry-instrument rocannon mcp serve …`
|
|
52
|
+
otel = [
|
|
53
|
+
"opentelemetry-sdk>=1.42.1",
|
|
54
|
+
"opentelemetry-exporter-otlp>=1.42.1",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
# --- Meta ---
|
|
58
|
+
# `pip install 'rocannon[all]'`, everything.
|
|
59
|
+
all = [
|
|
60
|
+
"ansible-core>=2.21.0",
|
|
61
|
+
"ansible-runner>=2.4.3",
|
|
62
|
+
"litellm>=1.89.0",
|
|
63
|
+
"opentelemetry-sdk>=1.42.1",
|
|
64
|
+
"opentelemetry-exporter-otlp>=1.42.1",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[project.urls]
|
|
68
|
+
Homepage = "https://github.com/msradam/rocannon"
|
|
69
|
+
Repository = "https://github.com/msradam/rocannon"
|
|
70
|
+
Issues = "https://github.com/msradam/rocannon/issues"
|
|
71
|
+
|
|
72
|
+
[project.scripts]
|
|
73
|
+
rocannon = "rocannon.cli:main"
|
|
74
|
+
|
|
75
|
+
[build-system]
|
|
76
|
+
requires = ["uv_build>=0.11.14,<0.12.0"]
|
|
77
|
+
build-backend = "uv_build"
|
|
78
|
+
|
|
79
|
+
[dependency-groups]
|
|
80
|
+
# `uv sync` installs these alongside the project. Includes the `ansible` extra's
|
|
81
|
+
# Python deps so the test suite + lint can run against the full codebase.
|
|
82
|
+
dev = [
|
|
83
|
+
"ansible-core>=2.21.0",
|
|
84
|
+
"ansible-runner>=2.4.3",
|
|
85
|
+
"litellm>=1.89.0",
|
|
86
|
+
"mypy>=2.1.0",
|
|
87
|
+
"opentelemetry-sdk>=1.42.1",
|
|
88
|
+
"ollama>=0.6.2",
|
|
89
|
+
"pre-commit>=4.6.0",
|
|
90
|
+
"pytest>=9.1.0",
|
|
91
|
+
"pytest-asyncio>=1.4.0",
|
|
92
|
+
"pytest-cov>=7.1.0",
|
|
93
|
+
"ruff>=0.15.17",
|
|
94
|
+
"types-pyyaml>=6.0.12.20260518",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
[tool.pytest.ini_options]
|
|
98
|
+
asyncio_mode = "auto"
|
|
99
|
+
# Collect only the tracked suite by default. dev/tests/ holds local LLM evals
|
|
100
|
+
# that hit a real model; running them is opt-in via an explicit path.
|
|
101
|
+
testpaths = ["tests"]
|
|
102
|
+
markers = [
|
|
103
|
+
"integration: end-to-end tests that touch real docker/ansible. Opt-in via `pytest -m integration`.",
|
|
104
|
+
]
|
|
105
|
+
# Default: run unit tests, skip integration. Override with `pytest -m integration`.
|
|
106
|
+
addopts = "-m 'not integration'"
|
|
107
|
+
|
|
108
|
+
[tool.coverage.run]
|
|
109
|
+
branch = true
|
|
110
|
+
source = ["src/rocannon"]
|
|
111
|
+
omit = ["src/rocannon/__main__.py"]
|
|
112
|
+
|
|
113
|
+
[tool.coverage.report]
|
|
114
|
+
show_missing = true
|
|
115
|
+
skip_covered = false
|
|
116
|
+
exclude_lines = [
|
|
117
|
+
"pragma: no cover",
|
|
118
|
+
"if __name__ == .__main__.:",
|
|
119
|
+
"raise NotImplementedError",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
# --- Ruff ---
|
|
123
|
+
[tool.ruff]
|
|
124
|
+
line-length = 100
|
|
125
|
+
target-version = "py312"
|
|
126
|
+
src = ["src"]
|
|
127
|
+
|
|
128
|
+
[tool.ruff.lint]
|
|
129
|
+
select = ["E", "W", "F", "I", "N", "UP", "B", "C4", "SIM", "S", "FURB"]
|
|
130
|
+
|
|
131
|
+
[tool.ruff.lint.per-file-ignores]
|
|
132
|
+
"tests/**" = ["S101", "S105", "S108", "S110", "S310", "S603", "S607"]
|
|
133
|
+
"src/rocannon/schema.py" = ["S603", "S607"]
|
|
134
|
+
"src/rocannon/inventory.py" = ["S603"]
|
|
135
|
+
"src/rocannon/cli.py" = ["S603", "S607"]
|
|
136
|
+
|
|
137
|
+
[tool.ruff.format]
|
|
138
|
+
quote-style = "double"
|
|
139
|
+
|
|
140
|
+
# --- Mypy ---
|
|
141
|
+
[tool.mypy]
|
|
142
|
+
python_version = "3.12"
|
|
143
|
+
strict = true
|
|
144
|
+
disallow_untyped_defs = true
|
|
145
|
+
warn_return_any = true
|
|
146
|
+
warn_unused_ignores = true
|
|
147
|
+
warn_redundant_casts = true
|
|
148
|
+
no_implicit_reexport = true
|
|
149
|
+
mypy_path = "src"
|
|
150
|
+
|
|
151
|
+
# Third-party libs without bundled type stubs. ansible_runner ships
|
|
152
|
+
# partial stubs only.
|
|
153
|
+
[[tool.mypy.overrides]]
|
|
154
|
+
module = ["ansible_runner.*"]
|
|
155
|
+
ignore_missing_imports = true
|
|
File without changes
|