yandex-cli 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.
Files changed (116) hide show
  1. yandex_cli-0.1.0/.gitignore +28 -0
  2. yandex_cli-0.1.0/CHANGELOG.md +17 -0
  3. yandex_cli-0.1.0/LICENSE +21 -0
  4. yandex_cli-0.1.0/PKG-INFO +240 -0
  5. yandex_cli-0.1.0/README.md +209 -0
  6. yandex_cli-0.1.0/pyproject.toml +91 -0
  7. yandex_cli-0.1.0/src/ycli/__init__.py +13 -0
  8. yandex_cli-0.1.0/src/ycli/cli.py +58 -0
  9. yandex_cli-0.1.0/src/ycli/log.py +27 -0
  10. yandex_cli-0.1.0/src/ycli/mcp.py +31 -0
  11. yandex_cli-0.1.0/src/ycli/yandex/__init__.py +0 -0
  12. yandex_cli-0.1.0/src/ycli/yandex/base.py +67 -0
  13. yandex_cli-0.1.0/src/ycli/yandex/forms/__init__.py +1 -0
  14. yandex_cli-0.1.0/src/ycli/yandex/forms/_base.py +17 -0
  15. yandex_cli-0.1.0/src/ycli/yandex/forms/_clideps.py +20 -0
  16. yandex_cli-0.1.0/src/ycli/yandex/forms/_deps.py +10 -0
  17. yandex_cli-0.1.0/src/ycli/yandex/forms/_models.py +18 -0
  18. yandex_cli-0.1.0/src/ycli/yandex/forms/answers/__init__.py +1 -0
  19. yandex_cli-0.1.0/src/ycli/yandex/forms/answers/cli.py +25 -0
  20. yandex_cli-0.1.0/src/ycli/yandex/forms/answers/client.py +57 -0
  21. yandex_cli-0.1.0/src/ycli/yandex/forms/answers/mcp.py +15 -0
  22. yandex_cli-0.1.0/src/ycli/yandex/forms/answers/models.py +54 -0
  23. yandex_cli-0.1.0/src/ycli/yandex/forms/cli.py +16 -0
  24. yandex_cli-0.1.0/src/ycli/yandex/forms/client.py +29 -0
  25. yandex_cli-0.1.0/src/ycli/yandex/forms/mcp.py +13 -0
  26. yandex_cli-0.1.0/src/ycli/yandex/forms/me/__init__.py +1 -0
  27. yandex_cli-0.1.0/src/ycli/yandex/forms/me/cli.py +19 -0
  28. yandex_cli-0.1.0/src/ycli/yandex/forms/me/client.py +25 -0
  29. yandex_cli-0.1.0/src/ycli/yandex/forms/me/mcp.py +20 -0
  30. yandex_cli-0.1.0/src/ycli/yandex/forms/me/models.py +18 -0
  31. yandex_cli-0.1.0/src/ycli/yandex/forms/questions/__init__.py +1 -0
  32. yandex_cli-0.1.0/src/ycli/yandex/forms/questions/cli.py +25 -0
  33. yandex_cli-0.1.0/src/ycli/yandex/forms/questions/client.py +24 -0
  34. yandex_cli-0.1.0/src/ycli/yandex/forms/questions/mcp.py +15 -0
  35. yandex_cli-0.1.0/src/ycli/yandex/forms/questions/models.py +46 -0
  36. yandex_cli-0.1.0/src/ycli/yandex/forms/surveys/__init__.py +1 -0
  37. yandex_cli-0.1.0/src/ycli/yandex/forms/surveys/cli.py +26 -0
  38. yandex_cli-0.1.0/src/ycli/yandex/forms/surveys/client.py +36 -0
  39. yandex_cli-0.1.0/src/ycli/yandex/forms/surveys/mcp.py +26 -0
  40. yandex_cli-0.1.0/src/ycli/yandex/forms/surveys/models.py +44 -0
  41. yandex_cli-0.1.0/src/ycli/yandex/tracker/__init__.py +1 -0
  42. yandex_cli-0.1.0/src/ycli/yandex/tracker/_base.py +14 -0
  43. yandex_cli-0.1.0/src/ycli/yandex/tracker/_clideps.py +46 -0
  44. yandex_cli-0.1.0/src/ycli/yandex/tracker/_deps.py +10 -0
  45. yandex_cli-0.1.0/src/ycli/yandex/tracker/_models.py +48 -0
  46. yandex_cli-0.1.0/src/ycli/yandex/tracker/changelog/__init__.py +1 -0
  47. yandex_cli-0.1.0/src/ycli/yandex/tracker/changelog/cli.py +25 -0
  48. yandex_cli-0.1.0/src/ycli/yandex/tracker/changelog/client.py +28 -0
  49. yandex_cli-0.1.0/src/ycli/yandex/tracker/changelog/mcp.py +15 -0
  50. yandex_cli-0.1.0/src/ycli/yandex/tracker/changelog/models.py +58 -0
  51. yandex_cli-0.1.0/src/ycli/yandex/tracker/cli.py +26 -0
  52. yandex_cli-0.1.0/src/ycli/yandex/tracker/client.py +39 -0
  53. yandex_cli-0.1.0/src/ycli/yandex/tracker/comments/__init__.py +1 -0
  54. yandex_cli-0.1.0/src/ycli/yandex/tracker/comments/cli.py +28 -0
  55. yandex_cli-0.1.0/src/ycli/yandex/tracker/comments/client.py +37 -0
  56. yandex_cli-0.1.0/src/ycli/yandex/tracker/comments/mcp.py +15 -0
  57. yandex_cli-0.1.0/src/ycli/yandex/tracker/comments/models.py +34 -0
  58. yandex_cli-0.1.0/src/ycli/yandex/tracker/issues/__init__.py +1 -0
  59. yandex_cli-0.1.0/src/ycli/yandex/tracker/issues/cli.py +132 -0
  60. yandex_cli-0.1.0/src/ycli/yandex/tracker/issues/client.py +92 -0
  61. yandex_cli-0.1.0/src/ycli/yandex/tracker/issues/mcp.py +53 -0
  62. yandex_cli-0.1.0/src/ycli/yandex/tracker/issues/models.py +73 -0
  63. yandex_cli-0.1.0/src/ycli/yandex/tracker/issuetypes/__init__.py +1 -0
  64. yandex_cli-0.1.0/src/ycli/yandex/tracker/issuetypes/cli.py +19 -0
  65. yandex_cli-0.1.0/src/ycli/yandex/tracker/issuetypes/client.py +24 -0
  66. yandex_cli-0.1.0/src/ycli/yandex/tracker/issuetypes/mcp.py +15 -0
  67. yandex_cli-0.1.0/src/ycli/yandex/tracker/issuetypes/models.py +27 -0
  68. yandex_cli-0.1.0/src/ycli/yandex/tracker/links/__init__.py +1 -0
  69. yandex_cli-0.1.0/src/ycli/yandex/tracker/links/cli.py +43 -0
  70. yandex_cli-0.1.0/src/ycli/yandex/tracker/links/client.py +37 -0
  71. yandex_cli-0.1.0/src/ycli/yandex/tracker/links/mcp.py +15 -0
  72. yandex_cli-0.1.0/src/ycli/yandex/tracker/links/models.py +56 -0
  73. yandex_cli-0.1.0/src/ycli/yandex/tracker/linktypes/__init__.py +1 -0
  74. yandex_cli-0.1.0/src/ycli/yandex/tracker/linktypes/cli.py +19 -0
  75. yandex_cli-0.1.0/src/ycli/yandex/tracker/linktypes/client.py +24 -0
  76. yandex_cli-0.1.0/src/ycli/yandex/tracker/linktypes/mcp.py +15 -0
  77. yandex_cli-0.1.0/src/ycli/yandex/tracker/linktypes/models.py +28 -0
  78. yandex_cli-0.1.0/src/ycli/yandex/tracker/mcp.py +23 -0
  79. yandex_cli-0.1.0/src/ycli/yandex/tracker/priorities/__init__.py +1 -0
  80. yandex_cli-0.1.0/src/ycli/yandex/tracker/priorities/cli.py +19 -0
  81. yandex_cli-0.1.0/src/ycli/yandex/tracker/priorities/client.py +24 -0
  82. yandex_cli-0.1.0/src/ycli/yandex/tracker/priorities/mcp.py +15 -0
  83. yandex_cli-0.1.0/src/ycli/yandex/tracker/priorities/models.py +27 -0
  84. yandex_cli-0.1.0/src/ycli/yandex/tracker/transitions/__init__.py +1 -0
  85. yandex_cli-0.1.0/src/ycli/yandex/tracker/transitions/cli.py +34 -0
  86. yandex_cli-0.1.0/src/ycli/yandex/tracker/transitions/client.py +52 -0
  87. yandex_cli-0.1.0/src/ycli/yandex/tracker/transitions/mcp.py +15 -0
  88. yandex_cli-0.1.0/src/ycli/yandex/tracker/transitions/models.py +27 -0
  89. yandex_cli-0.1.0/src/ycli/yandex/tracker/worklog/__init__.py +1 -0
  90. yandex_cli-0.1.0/src/ycli/yandex/tracker/worklog/cli.py +21 -0
  91. yandex_cli-0.1.0/src/ycli/yandex/tracker/worklog/client.py +24 -0
  92. yandex_cli-0.1.0/src/ycli/yandex/tracker/worklog/mcp.py +15 -0
  93. yandex_cli-0.1.0/src/ycli/yandex/tracker/worklog/models.py +36 -0
  94. yandex_cli-0.1.0/src/ycli/yandex/transport.py +116 -0
  95. yandex_cli-0.1.0/src/ycli/yandex/wiki/__init__.py +1 -0
  96. yandex_cli-0.1.0/src/ycli/yandex/wiki/_base.py +8 -0
  97. yandex_cli-0.1.0/src/ycli/yandex/wiki/_clideps.py +20 -0
  98. yandex_cli-0.1.0/src/ycli/yandex/wiki/_deps.py +10 -0
  99. yandex_cli-0.1.0/src/ycli/yandex/wiki/attachments/__init__.py +0 -0
  100. yandex_cli-0.1.0/src/ycli/yandex/wiki/attachments/cli.py +20 -0
  101. yandex_cli-0.1.0/src/ycli/yandex/wiki/attachments/client.py +29 -0
  102. yandex_cli-0.1.0/src/ycli/yandex/wiki/attachments/mcp.py +15 -0
  103. yandex_cli-0.1.0/src/ycli/yandex/wiki/attachments/models.py +32 -0
  104. yandex_cli-0.1.0/src/ycli/yandex/wiki/cli.py +14 -0
  105. yandex_cli-0.1.0/src/ycli/yandex/wiki/client.py +27 -0
  106. yandex_cli-0.1.0/src/ycli/yandex/wiki/comments/__init__.py +0 -0
  107. yandex_cli-0.1.0/src/ycli/yandex/wiki/comments/cli.py +20 -0
  108. yandex_cli-0.1.0/src/ycli/yandex/wiki/comments/client.py +29 -0
  109. yandex_cli-0.1.0/src/ycli/yandex/wiki/comments/mcp.py +15 -0
  110. yandex_cli-0.1.0/src/ycli/yandex/wiki/comments/models.py +40 -0
  111. yandex_cli-0.1.0/src/ycli/yandex/wiki/mcp.py +11 -0
  112. yandex_cli-0.1.0/src/ycli/yandex/wiki/pages/__init__.py +0 -0
  113. yandex_cli-0.1.0/src/ycli/yandex/wiki/pages/cli.py +64 -0
  114. yandex_cli-0.1.0/src/ycli/yandex/wiki/pages/client.py +74 -0
  115. yandex_cli-0.1.0/src/ycli/yandex/wiki/pages/mcp.py +32 -0
  116. yandex_cli-0.1.0/src/ycli/yandex/wiki/pages/models.py +82 -0
@@ -0,0 +1,28 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ build/
8
+ dist/
9
+ wheels/
10
+
11
+ # Virtual envs / tooling caches
12
+ .venv/
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+
17
+ # Coverage
18
+ .coverage
19
+ .coverage.*
20
+ coverage.xml
21
+ htmlcov/
22
+
23
+ # AI-agent local files
24
+ PROMPT.md
25
+ .mcp.json
26
+
27
+ # Secrets
28
+ .env
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] — 2026-06-27
10
+
11
+ ### Added
12
+ - Initial release: Yandex 360 toolkit for **Tracker**, **Wiki**, and **Forms**.
13
+ - Four surfaces from one codebase: Typer **CLI** (`ycli` / `yandex-cli`), FastMCP **server**
14
+ (`ycli mcp`, read-only, `[mcp]` extra), importable **Python SDK** (`ycli.yandex.*`), and a
15
+ **Claude Code plugin** (`plugins/yandex-360/`).
16
+ - Published on PyPI as **`yandex-cli`** (`uv add yandex-cli`, or `yandex-cli[mcp]` for the server).
17
+ - Test suite at 100% coverage with `responses`-stubbed HTTP.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sava Znatnov
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.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: yandex-cli
3
+ Version: 0.1.0
4
+ Summary: Interact with Yandex 360 services (Wiki, Tracker, Forms, …) from a CLI, an MCP server, or a Python SDK.
5
+ Project-URL: Homepage, https://github.com/bim-ba/ycli
6
+ Project-URL: Repository, https://github.com/bim-ba/ycli
7
+ Project-URL: Issues, https://github.com/bim-ba/ycli/issues
8
+ Project-URL: Changelog, https://github.com/bim-ba/ycli/blob/main/CHANGELOG.md
9
+ Author-email: Sava Znatnov <careless.sava@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,fastmcp,forms,mcp,sdk,tracker,typer,wiki,yandex,yandex-360
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.12
23
+ Requires-Dist: loguru>=0.7.3
24
+ Requires-Dist: pydantic>=2.13.4
25
+ Requires-Dist: requests>=2.34.2
26
+ Requires-Dist: typer>=0.26.8
27
+ Requires-Dist: uplink>=0.10.0
28
+ Provides-Extra: mcp
29
+ Requires-Dist: fastmcp>=3.4.2; extra == 'mcp'
30
+ Description-Content-Type: text/markdown
31
+
32
+ <div align="center">
33
+
34
+ # ycli
35
+
36
+ **One Yandex 360 toolkit — four ways to use it.**
37
+ Drive **Tracker**, **Wiki**, and **Forms** from a CLI, an MCP server, a Python SDK,
38
+ or a Claude Code plugin. Built for AI agents first — pleasant for humans too.
39
+
40
+ [![CI](https://img.shields.io/github/actions/workflow/status/bim-ba/ycli/ci.yml?branch=main&style=for-the-badge)](https://github.com/bim-ba/ycli/actions/workflows/ci.yml)
41
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen?style=for-the-badge)](https://github.com/bim-ba/ycli)
42
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
43
+ [![License](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)
44
+ [![MCP](https://img.shields.io/badge/MCP-compatible-7c3aed?style=for-the-badge)](https://modelcontextprotocol.io/)
45
+ [![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-d97757?style=for-the-badge)](plugins/yandex-360/)
46
+
47
+ <img src="https://raw.githubusercontent.com/bim-ba/ycli/main/docs/assets/demo.gif" alt="ycli in action" width="760">
48
+
49
+ </div>
50
+
51
+ ## Why ycli
52
+
53
+ - 🧩 **One SDK, four surfaces** — write logic once, use it as a CLI, an MCP server, a Python
54
+ library, or a Claude Code plugin.
55
+ - 🤖 **Agent-native** — the MCP server exposes read-only `tracker_*`, `wiki_*`, `forms_*`
56
+ tools so agents explore safely; writes stay in the CLI/SDK.
57
+ - 🛡️ **Trustworthy** — typed pydantic models, the real Yandex API quirks handled for you,
58
+ and a test suite kept at **100% coverage**.
59
+ - ⚡ **Zero-friction start** — `uv add yandex-cli`, two env vars, go.
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ uv add yandex-cli # CLI + Python SDK
65
+ uv add 'yandex-cli[mcp]' # …plus the MCP server (`ycli mcp`)
66
+ ```
67
+
68
+ Run it without installing, or install it as a standalone tool:
69
+
70
+ ```bash
71
+ uvx yandex-cli --help # one-off, no install
72
+ uv tool install yandex-cli # persistent CLI
73
+ uv tool install 'yandex-cli[mcp]' # …with the MCP server
74
+ ```
75
+
76
+ `pip install yandex-cli` works too. The CLI ships as both `yandex-cli` and the short `ycli`.
77
+
78
+ ## Quick start
79
+
80
+ Pick the surface that fits how you work.
81
+
82
+ <details open>
83
+ <summary><b>CLI</b></summary>
84
+
85
+ ```bash
86
+ uv add yandex-cli
87
+ ycli --help
88
+ ycli tracker issues get TRACKER-1
89
+ ycli wiki pages get onboarding
90
+ ```
91
+ </details>
92
+
93
+ <details>
94
+ <summary><b>MCP server</b> (read-only)</summary>
95
+
96
+ Run it over stdio (needs the `mcp` extra):
97
+
98
+ ```bash
99
+ ycli mcp
100
+ ```
101
+
102
+ Point an MCP client at it — no prior install needed via `uvx` (tools are namespaced
103
+ `tracker_*`, `wiki_*`, `forms_*`):
104
+
105
+ ```json
106
+ {
107
+ "mcpServers": {
108
+ "yandex": {
109
+ "command": "uvx",
110
+ "args": ["--from", "yandex-cli[mcp]", "ycli", "mcp"],
111
+ "env": {
112
+ "YANDEX_ID_OAUTH_TOKEN": "...",
113
+ "YANDEX_ID_ORGANIZATION_ID": "..."
114
+ }
115
+ }
116
+ }
117
+ }
118
+ ```
119
+ </details>
120
+
121
+ <details>
122
+ <summary><b>Python SDK</b></summary>
123
+
124
+ ```python
125
+ from ycli.yandex.tracker.client import TrackerClient
126
+
127
+ tracker = TrackerClient.from_env()
128
+ issue = tracker.issues.get("TRACKER-1")
129
+ print(issue.summary)
130
+ ```
131
+ </details>
132
+
133
+ <details>
134
+ <summary><b>Claude Code plugin</b></summary>
135
+
136
+ ```
137
+ /plugin marketplace add bim-ba/ycli
138
+ /plugin install yandex-360@ycli
139
+ ```
140
+
141
+ Teaches an agent to drive Yandex 360 through `ycli` — including the real API quirks.
142
+ See [`plugins/yandex-360/`](plugins/yandex-360/).
143
+ </details>
144
+
145
+ ## Skills (Claude Code plugin)
146
+
147
+ | Skill | Use for |
148
+ |-------|---------|
149
+ | `yandex-360` | Entry point — install + auth, pick a surface (CLI/MCP/SDK), route to a domain |
150
+ | `yandex-360-tracker` | Issues, epics, comments, transitions, links, worklog, changelog |
151
+ | `yandex-360-wiki` | Wiki pages, page tree, comments, attachments, YFM authoring |
152
+ | `yandex-360-forms` | Forms, questions/schema, responses, pagination |
153
+
154
+ The skills encode the read/write commands **and** the gnarly Yandex API quirks
155
+ (epic-vs-parent, transition discovery, permanent wiki slugs, `fields=` rules, Forms
156
+ host/header traps, answers pagination).
157
+
158
+ ## What's covered
159
+
160
+ Reads ship across **SDK + CLI + MCP**; writes across **SDK + CLI** only (the MCP server is
161
+ read-only by design).
162
+
163
+ ### Tracker
164
+
165
+ | Resource | Operations | SDK | CLI | MCP |
166
+ |----------|-----------|:---:|:---:|:---:|
167
+ | issues | get · full · search · list · count | ✅ | ✅ | ✅ |
168
+ | issues | create · update | ✅ | ✅ | — |
169
+ | comments | list | ✅ | ✅ | ✅ |
170
+ | comments | add | ✅ | ✅ | — |
171
+ | links | list | ✅ | ✅ | ✅ |
172
+ | links | add | ✅ | ✅ | — |
173
+ | transitions | list | ✅ | ✅ | ✅ |
174
+ | transitions | execute | ✅ | ✅ | — |
175
+ | worklog · changelog · priorities · issuetypes · linktypes | list | ✅ | ✅ | ✅ |
176
+
177
+ ### Wiki
178
+
179
+ | Resource | Operations | SDK | CLI | MCP |
180
+ |----------|-----------|:---:|:---:|:---:|
181
+ | pages | get · descendants | ✅ | ✅ | ✅ |
182
+ | pages | meta (metadata-only) | — | — | ✅ |
183
+ | pages | create · update | ✅ | ✅ | — |
184
+ | comments | list | ✅ | ✅ | ✅ |
185
+ | attachments | list | ✅ | ✅ | ✅ |
186
+
187
+ ### Forms (read-only today)
188
+
189
+ | Resource | Operations | SDK | CLI | MCP |
190
+ |----------|-----------|:---:|:---:|:---:|
191
+ | me | get (whoami) | ✅ | ✅ | ✅ |
192
+ | surveys | list · get | ✅ | ✅ | ✅ |
193
+ | questions | list | ✅ | ✅ | ✅ |
194
+ | answers | list (drains all pages) | ✅ | ✅ | ✅ |
195
+
196
+ > **Mail and more — coming.** See [`docs/api-coverage.md`](docs/api-coverage.md) for the full
197
+ > gap analysis and prioritized roadmap.
198
+
199
+ ## Configure
200
+
201
+ ```bash
202
+ cp .env.example .env
203
+ ```
204
+
205
+ ```bash
206
+ YANDEX_ID_OAUTH_TOKEN=... # get one at https://oauth.yandex.ru/
207
+ YANDEX_ID_ORGANIZATION_ID=... # from the Yandex 360 admin panel
208
+ ```
209
+
210
+ Header casing differs per service (Tracker `X-Org-ID`, Wiki/Forms `X-Org-Id`) — ycli
211
+ handles it for you.
212
+
213
+ ## Project layout
214
+
215
+ ```text
216
+ src/ycli/
217
+ ├── cli.py # root Typer CLI → `ycli` / `yandex-cli`
218
+ ├── mcp.py # root FastMCP server → `ycli mcp` (read-only, `[mcp]` extra)
219
+ ├── log.py # central loguru config
220
+ └── yandex/
221
+ ├── tracker/ # per-domain SDK …
222
+ ├── wiki/ # each resource group has:
223
+ └── forms/ # client.py · cli.py · mcp.py · models.py
224
+ plugins/yandex-360/ # distributable Claude Code plugin (skills + instructions)
225
+ docs/references/ # vendored Yandex API reference docs
226
+ ```
227
+
228
+ ## Development
229
+
230
+ ```bash
231
+ uv sync --all-extras # --all-extras pulls in the `mcp` extra the tests exercise
232
+ uv run pytest # 100% coverage gate; HTTP stubbed with `responses` (no live network)
233
+ ```
234
+
235
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for conventions. Contributions welcome — the
236
+ [coverage roadmap](docs/api-coverage.md) is a good place to find a first issue.
237
+
238
+ ## License
239
+
240
+ [MIT](LICENSE) © 2026 Sava Znatnov
@@ -0,0 +1,209 @@
1
+ <div align="center">
2
+
3
+ # ycli
4
+
5
+ **One Yandex 360 toolkit — four ways to use it.**
6
+ Drive **Tracker**, **Wiki**, and **Forms** from a CLI, an MCP server, a Python SDK,
7
+ or a Claude Code plugin. Built for AI agents first — pleasant for humans too.
8
+
9
+ [![CI](https://img.shields.io/github/actions/workflow/status/bim-ba/ycli/ci.yml?branch=main&style=for-the-badge)](https://github.com/bim-ba/ycli/actions/workflows/ci.yml)
10
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen?style=for-the-badge)](https://github.com/bim-ba/ycli)
11
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
12
+ [![License](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)
13
+ [![MCP](https://img.shields.io/badge/MCP-compatible-7c3aed?style=for-the-badge)](https://modelcontextprotocol.io/)
14
+ [![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin-d97757?style=for-the-badge)](plugins/yandex-360/)
15
+
16
+ <img src="https://raw.githubusercontent.com/bim-ba/ycli/main/docs/assets/demo.gif" alt="ycli in action" width="760">
17
+
18
+ </div>
19
+
20
+ ## Why ycli
21
+
22
+ - 🧩 **One SDK, four surfaces** — write logic once, use it as a CLI, an MCP server, a Python
23
+ library, or a Claude Code plugin.
24
+ - 🤖 **Agent-native** — the MCP server exposes read-only `tracker_*`, `wiki_*`, `forms_*`
25
+ tools so agents explore safely; writes stay in the CLI/SDK.
26
+ - 🛡️ **Trustworthy** — typed pydantic models, the real Yandex API quirks handled for you,
27
+ and a test suite kept at **100% coverage**.
28
+ - ⚡ **Zero-friction start** — `uv add yandex-cli`, two env vars, go.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ uv add yandex-cli # CLI + Python SDK
34
+ uv add 'yandex-cli[mcp]' # …plus the MCP server (`ycli mcp`)
35
+ ```
36
+
37
+ Run it without installing, or install it as a standalone tool:
38
+
39
+ ```bash
40
+ uvx yandex-cli --help # one-off, no install
41
+ uv tool install yandex-cli # persistent CLI
42
+ uv tool install 'yandex-cli[mcp]' # …with the MCP server
43
+ ```
44
+
45
+ `pip install yandex-cli` works too. The CLI ships as both `yandex-cli` and the short `ycli`.
46
+
47
+ ## Quick start
48
+
49
+ Pick the surface that fits how you work.
50
+
51
+ <details open>
52
+ <summary><b>CLI</b></summary>
53
+
54
+ ```bash
55
+ uv add yandex-cli
56
+ ycli --help
57
+ ycli tracker issues get TRACKER-1
58
+ ycli wiki pages get onboarding
59
+ ```
60
+ </details>
61
+
62
+ <details>
63
+ <summary><b>MCP server</b> (read-only)</summary>
64
+
65
+ Run it over stdio (needs the `mcp` extra):
66
+
67
+ ```bash
68
+ ycli mcp
69
+ ```
70
+
71
+ Point an MCP client at it — no prior install needed via `uvx` (tools are namespaced
72
+ `tracker_*`, `wiki_*`, `forms_*`):
73
+
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "yandex": {
78
+ "command": "uvx",
79
+ "args": ["--from", "yandex-cli[mcp]", "ycli", "mcp"],
80
+ "env": {
81
+ "YANDEX_ID_OAUTH_TOKEN": "...",
82
+ "YANDEX_ID_ORGANIZATION_ID": "..."
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ```
88
+ </details>
89
+
90
+ <details>
91
+ <summary><b>Python SDK</b></summary>
92
+
93
+ ```python
94
+ from ycli.yandex.tracker.client import TrackerClient
95
+
96
+ tracker = TrackerClient.from_env()
97
+ issue = tracker.issues.get("TRACKER-1")
98
+ print(issue.summary)
99
+ ```
100
+ </details>
101
+
102
+ <details>
103
+ <summary><b>Claude Code plugin</b></summary>
104
+
105
+ ```
106
+ /plugin marketplace add bim-ba/ycli
107
+ /plugin install yandex-360@ycli
108
+ ```
109
+
110
+ Teaches an agent to drive Yandex 360 through `ycli` — including the real API quirks.
111
+ See [`plugins/yandex-360/`](plugins/yandex-360/).
112
+ </details>
113
+
114
+ ## Skills (Claude Code plugin)
115
+
116
+ | Skill | Use for |
117
+ |-------|---------|
118
+ | `yandex-360` | Entry point — install + auth, pick a surface (CLI/MCP/SDK), route to a domain |
119
+ | `yandex-360-tracker` | Issues, epics, comments, transitions, links, worklog, changelog |
120
+ | `yandex-360-wiki` | Wiki pages, page tree, comments, attachments, YFM authoring |
121
+ | `yandex-360-forms` | Forms, questions/schema, responses, pagination |
122
+
123
+ The skills encode the read/write commands **and** the gnarly Yandex API quirks
124
+ (epic-vs-parent, transition discovery, permanent wiki slugs, `fields=` rules, Forms
125
+ host/header traps, answers pagination).
126
+
127
+ ## What's covered
128
+
129
+ Reads ship across **SDK + CLI + MCP**; writes across **SDK + CLI** only (the MCP server is
130
+ read-only by design).
131
+
132
+ ### Tracker
133
+
134
+ | Resource | Operations | SDK | CLI | MCP |
135
+ |----------|-----------|:---:|:---:|:---:|
136
+ | issues | get · full · search · list · count | ✅ | ✅ | ✅ |
137
+ | issues | create · update | ✅ | ✅ | — |
138
+ | comments | list | ✅ | ✅ | ✅ |
139
+ | comments | add | ✅ | ✅ | — |
140
+ | links | list | ✅ | ✅ | ✅ |
141
+ | links | add | ✅ | ✅ | — |
142
+ | transitions | list | ✅ | ✅ | ✅ |
143
+ | transitions | execute | ✅ | ✅ | — |
144
+ | worklog · changelog · priorities · issuetypes · linktypes | list | ✅ | ✅ | ✅ |
145
+
146
+ ### Wiki
147
+
148
+ | Resource | Operations | SDK | CLI | MCP |
149
+ |----------|-----------|:---:|:---:|:---:|
150
+ | pages | get · descendants | ✅ | ✅ | ✅ |
151
+ | pages | meta (metadata-only) | — | — | ✅ |
152
+ | pages | create · update | ✅ | ✅ | — |
153
+ | comments | list | ✅ | ✅ | ✅ |
154
+ | attachments | list | ✅ | ✅ | ✅ |
155
+
156
+ ### Forms (read-only today)
157
+
158
+ | Resource | Operations | SDK | CLI | MCP |
159
+ |----------|-----------|:---:|:---:|:---:|
160
+ | me | get (whoami) | ✅ | ✅ | ✅ |
161
+ | surveys | list · get | ✅ | ✅ | ✅ |
162
+ | questions | list | ✅ | ✅ | ✅ |
163
+ | answers | list (drains all pages) | ✅ | ✅ | ✅ |
164
+
165
+ > **Mail and more — coming.** See [`docs/api-coverage.md`](docs/api-coverage.md) for the full
166
+ > gap analysis and prioritized roadmap.
167
+
168
+ ## Configure
169
+
170
+ ```bash
171
+ cp .env.example .env
172
+ ```
173
+
174
+ ```bash
175
+ YANDEX_ID_OAUTH_TOKEN=... # get one at https://oauth.yandex.ru/
176
+ YANDEX_ID_ORGANIZATION_ID=... # from the Yandex 360 admin panel
177
+ ```
178
+
179
+ Header casing differs per service (Tracker `X-Org-ID`, Wiki/Forms `X-Org-Id`) — ycli
180
+ handles it for you.
181
+
182
+ ## Project layout
183
+
184
+ ```text
185
+ src/ycli/
186
+ ├── cli.py # root Typer CLI → `ycli` / `yandex-cli`
187
+ ├── mcp.py # root FastMCP server → `ycli mcp` (read-only, `[mcp]` extra)
188
+ ├── log.py # central loguru config
189
+ └── yandex/
190
+ ├── tracker/ # per-domain SDK …
191
+ ├── wiki/ # each resource group has:
192
+ └── forms/ # client.py · cli.py · mcp.py · models.py
193
+ plugins/yandex-360/ # distributable Claude Code plugin (skills + instructions)
194
+ docs/references/ # vendored Yandex API reference docs
195
+ ```
196
+
197
+ ## Development
198
+
199
+ ```bash
200
+ uv sync --all-extras # --all-extras pulls in the `mcp` extra the tests exercise
201
+ uv run pytest # 100% coverage gate; HTTP stubbed with `responses` (no live network)
202
+ ```
203
+
204
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for conventions. Contributions welcome — the
205
+ [coverage roadmap](docs/api-coverage.md) is a good place to find a first issue.
206
+
207
+ ## License
208
+
209
+ [MIT](LICENSE) © 2026 Sava Znatnov
@@ -0,0 +1,91 @@
1
+ [project]
2
+ name = "yandex-cli"
3
+ version = "0.1.0"
4
+ description = "Interact with Yandex 360 services (Wiki, Tracker, Forms, …) from a CLI, an MCP server, or a Python SDK."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.12"
9
+ authors = [{ name = "Sava Znatnov", email = "careless.sava@gmail.com" }]
10
+ keywords = ["yandex", "yandex-360", "tracker", "wiki", "forms", "cli", "mcp", "sdk", "fastmcp", "typer"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: Developers",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ "Topic :: Utilities",
21
+ ]
22
+ dependencies = [
23
+ "loguru>=0.7.3",
24
+ "pydantic>=2.13.4",
25
+ "requests>=2.34.2",
26
+ "typer>=0.26.8",
27
+ "uplink>=0.10.0",
28
+ ]
29
+
30
+ # The MCP server (`ycli mcp`) is optional — install with `yandex-cli[mcp]`.
31
+ [project.optional-dependencies]
32
+ mcp = ["fastmcp>=3.4.2"]
33
+
34
+ [project.scripts]
35
+ yandex-cli = "ycli.cli:main"
36
+ ycli = "ycli.cli:main"
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/bim-ba/ycli"
40
+ Repository = "https://github.com/bim-ba/ycli"
41
+ Issues = "https://github.com/bim-ba/ycli/issues"
42
+ Changelog = "https://github.com/bim-ba/ycli/blob/main/CHANGELOG.md"
43
+
44
+ [build-system]
45
+ requires = ["hatchling"]
46
+ build-backend = "hatchling.build"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/ycli"]
50
+
51
+ # Keep the sdist lean: ship only the package + changelog (pyproject, README, and
52
+ # LICENSE are always included from metadata) — not the repo's docs, tests, Claude
53
+ # plugin, agent config, or vendored API references.
54
+ [tool.hatch.build.targets.sdist]
55
+ only-include = ["src/ycli", "CHANGELOG.md"]
56
+
57
+ # TestPyPI as an explicit publish target (used by `uv publish --index testpypi`).
58
+ # `explicit = true` keeps it out of normal dependency resolution.
59
+ [[tool.uv.index]]
60
+ name = "testpypi"
61
+ url = "https://test.pypi.org/simple/"
62
+ publish-url = "https://test.pypi.org/legacy/"
63
+ explicit = true
64
+
65
+ [tool.pytest.ini_options]
66
+ testpaths = ["tests"]
67
+ asyncio_mode = "auto"
68
+ addopts = "--cov=ycli --cov-report=term-missing --cov-fail-under=100"
69
+ markers = [
70
+ "integration: tests that exercise CLI/MCP wiring end-to-end (no live network)",
71
+ ]
72
+
73
+ [tool.coverage.run]
74
+ source = ["ycli"]
75
+
76
+ [tool.coverage.report]
77
+ show_missing = true
78
+ exclude_also = [
79
+ "if __name__ == .__main__.:",
80
+ "if TYPE_CHECKING:",
81
+ "raise NotImplementedError",
82
+ "\\.\\.\\.",
83
+ ]
84
+
85
+ [dependency-groups]
86
+ dev = [
87
+ "pytest>=9.1.1",
88
+ "pytest-asyncio>=1.4.0",
89
+ "pytest-cov>=7.1.0",
90
+ "responses>=0.26.1",
91
+ ]
@@ -0,0 +1,13 @@
1
+ """ycli — interact with Yandex 360 services (Wiki, Tracker, Forms, …).
2
+
3
+ One codebase, many surfaces: a Typer CLI (``ycli``), a FastMCP server (``ycli mcp``),
4
+ and an importable Python SDK under ``ycli.yandex``. Distributed on PyPI as ``yandex-cli``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from importlib.metadata import version
10
+
11
+ # Single source of truth: the version declared in pyproject.toml (read from installed
12
+ # metadata under the distribution name `yandex-cli`).
13
+ __version__ = version("yandex-cli")
@@ -0,0 +1,58 @@
1
+ """``ycli`` root CLI — mounts each domain's sub-app. Domain logic lives in <domain>/cli.py.
2
+
3
+ Run a subcommand directly: ``uv run ycli wiki pages get <slug>`` (or ``python -m ycli.cli``).
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import typer
9
+
10
+ from ycli.log import configure
11
+ from ycli.yandex.forms.cli import app as forms_app
12
+ from ycli.yandex.tracker.cli import app as tracker_app
13
+ from ycli.yandex.wiki.cli import app as wiki_app
14
+
15
+ app = typer.Typer(
16
+ name="ycli",
17
+ help="ycli — Yandex 360 API SDK CLI.",
18
+ no_args_is_help=True,
19
+ pretty_exceptions_show_locals=False,
20
+ add_completion=False,
21
+ )
22
+
23
+
24
+ @app.callback()
25
+ def _main() -> None:
26
+ """Configure logging once before any subcommand runs."""
27
+ configure()
28
+
29
+
30
+ app.add_typer(wiki_app)
31
+ app.add_typer(tracker_app)
32
+ app.add_typer(forms_app)
33
+
34
+
35
+ @app.command(name="mcp")
36
+ def mcp() -> None:
37
+ """Run the read-only MCP server over stdio (requires the ``mcp`` extra).
38
+
39
+ Tools are namespaced ``wiki_*``, ``tracker_*``, ``forms_*``. Point an MCP client
40
+ at ``ycli mcp``.
41
+ """
42
+ try:
43
+ from ycli.mcp import main as run_server
44
+ except ModuleNotFoundError as exc: # pragma: no cover - only without the 'mcp' extra
45
+ raise typer.BadParameter(
46
+ "The MCP server requires the 'mcp' extra. Install it with: "
47
+ "uv add 'yandex-cli[mcp]' (or: uv tool install 'yandex-cli[mcp]')."
48
+ ) from exc
49
+ run_server()
50
+
51
+
52
+ def main() -> None: # pragma: no cover
53
+ """Console-script entry point (``ycli`` / ``yandex-cli``)."""
54
+ app()
55
+
56
+
57
+ if __name__ == "__main__": # pragma: no cover
58
+ main()