annotide 0.1.0__tar.gz → 0.1.2__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.
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: annotide
3
+ Version: 0.1.2
4
+ Summary: Python SDK, CLI and MCP server for the Annotide annotation platform
5
+ Author: Annotide
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://annotide.com
8
+ Project-URL: Documentation, https://github.com/annotide/annotide/tree/main/sdk#readme
9
+ Project-URL: Source, https://github.com/annotide/annotide/tree/main/sdk
10
+ Project-URL: Issues, https://github.com/annotide/annotide/issues
11
+ Project-URL: Changelog, https://github.com/annotide/annotide/releases
12
+ Keywords: annotation,labeling,computer-vision,dataset,mlops,sdk,mcp
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ License-File: NOTICE
27
+ Requires-Dist: httpx>=0.27
28
+ Provides-Extra: mcp
29
+ Requires-Dist: mcp<3,>=2.2; extra == "mcp"
30
+ Provides-Extra: dev
31
+ Requires-Dist: mcp<3,>=2.2; extra == "dev"
32
+ Requires-Dist: pytest>=8.3; extra == "dev"
33
+ Requires-Dist: ruff>=0.8; extra == "dev"
34
+ Requires-Dist: mypy>=1.13; extra == "dev"
35
+ Requires-Dist: datamodel-code-generator>=0.83; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # annotide
39
+
40
+ Python SDK and command line for the Annotide API (API-3). One
41
+ runtime dependency (`httpx`); responses are plain dicts typed with
42
+ `TypedDict`s generated from the API's OpenAPI document.
43
+
44
+ ```sh
45
+ pip install annotide # or `pip install -e sdk` from a checkout
46
+ export ANNOTIDE_URL=https://annotate.example.com
47
+ export ANNOTIDE_API_KEY=... # Settings → API keys; use a service account for CI
48
+ ```
49
+
50
+ ## Python
51
+
52
+ ```python
53
+ from annotide import Client, JobFailedError
54
+
55
+ with Client() as client: # reads ANNOTIDE_URL / ANNOTIDE_API_KEY
56
+ project = next(p for p in client.list_projects() if p["name"] == "Cars")
57
+
58
+ # Freeze the dataset, then export it reproducibly.
59
+ snapshot = client.take_snapshot(
60
+ project["id"],
61
+ "2026-q3",
62
+ split={"train": 0.8, "val": 0.1, "test": 0.1, "seed": 0, "group_by": "folder"},
63
+ )
64
+ client.export(project["id"], "coco", "train.zip", snapshot_id=snapshot["id"], split="train")
65
+
66
+ # Import existing labels; a dry run reports what would happen.
67
+ report = client.import_file(project["id"], "labels.json", "coco", dry_run=True)
68
+ print(report["result"])
69
+ ```
70
+
71
+ - Errors are `ApiError` (`status`, `title`, `detail` from the RFC 9457
72
+ body); a job that ends `failed`/`cancelled` raises `JobFailedError`, one
73
+ that outlives its `timeout` raises `JobTimeoutError`.
74
+ - A 429 waits for `Retry-After` and repeats. Gateway errors (502/503/504)
75
+ repeat only when that is harmless: reads, and creates, which always carry
76
+ an `Idempotency-Key` so a repeat answers the first row.
77
+ - Export downloads go straight to storage with the signed URL; the API key
78
+ is never sent there.
79
+ - `client.request(method, path, ...)` reaches any endpoint without a method.
80
+
81
+ ## Command line
82
+
83
+ ```sh
84
+ annotide whoami
85
+ annotide projects list | jq -r '.name'
86
+ annotide snapshots create <project> 2026-q3 --split 0.8,0.1,0.1 --group-by folder
87
+ annotide export <project> --format coco --snapshot <id> --split train -o train.zip
88
+ annotide import <project> labels.json --format coco --class-map '{"auto": "car"}' --dry-run
89
+ annotide jobs wait <job>
90
+ ```
91
+
92
+ Lists print as JSON Lines, single objects as JSON; errors go to stderr with
93
+ exit status 1. The key is read from `ANNOTIDE_API_KEY` only, so it never
94
+ lands in shell history.
95
+
96
+ ## MCP server for AI agents (API-8)
97
+
98
+ `annotide mcp` serves the [Model Context Protocol](https://modelcontextprotocol.io)
99
+ over stdio, so an AI agent (Claude Code, Claude Desktop, or any MCP client)
100
+ can pre-label a project. It calls the REST API with an API key, so the agent
101
+ can do exactly what that account may do. It can list projects and their label
102
+ schema, view items (images come back as images), read annotations, claim and
103
+ release tasks, and post pre-labels. It cannot submit, review, delete or
104
+ export.
105
+
106
+ Setup, once per agent:
107
+
108
+ 1. **Service account.** Settings → API keys → Service accounts: create one,
109
+ mint a `write` key, and add the account to the project as an annotator.
110
+ 2. **Model.** Models → Register model, name it after the agent, and leave
111
+ the endpoint empty. That makes it an *external producer*: the platform
112
+ never calls it, and the agent posts the pre-labels. Add version 1 and
113
+ note its id.
114
+ 3. **Client config.** For Claude Code (`.mcp.json`) or Claude Desktop:
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "annotation": {
120
+ "command": "annotation",
121
+ "args": ["mcp"],
122
+ "env": {
123
+ "ANNOTIDE_URL": "https://annotate.example.com",
124
+ "ANNOTIDE_API_KEY": "ak_…",
125
+ "ANNOTIDE_MODEL_VERSION_ID": "<model version id>"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ Install with `pip install "annotide[mcp]"`. Pre-labels arrive as
133
+ `draft` versions authored by the model version. People review and submit
134
+ them as usual, and a pre-label never replaces human work (ML-10).
135
+
136
+ ## Development
137
+
138
+ ```sh
139
+ make install # from the repository root: creates sdk/.venv
140
+ cd sdk && .venv/bin/pytest && .venv/bin/mypy annotide tests tools
141
+ make openapi # after an API change: docs/openapi.json + models.py
142
+ ```
143
+
144
+ `annotide/models.py` is generated; never edit it by hand. CI fails when
145
+ it or `docs/openapi.json` is stale.
@@ -5,7 +5,7 @@ runtime dependency (`httpx`); responses are plain dicts typed with
5
5
  `TypedDict`s generated from the API's OpenAPI document.
6
6
 
7
7
  ```sh
8
- pip install -e sdk # from a checkout; not on a package index yet
8
+ pip install annotide # or `pip install -e sdk` from a checkout
9
9
  export ANNOTIDE_URL=https://annotate.example.com
10
10
  export ANNOTIDE_API_KEY=... # Settings → API keys; use a service account for CI
11
11
  ```
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: annotide
3
+ Version: 0.1.2
4
+ Summary: Python SDK, CLI and MCP server for the Annotide annotation platform
5
+ Author: Annotide
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://annotide.com
8
+ Project-URL: Documentation, https://github.com/annotide/annotide/tree/main/sdk#readme
9
+ Project-URL: Source, https://github.com/annotide/annotide/tree/main/sdk
10
+ Project-URL: Issues, https://github.com/annotide/annotide/issues
11
+ Project-URL: Changelog, https://github.com/annotide/annotide/releases
12
+ Keywords: annotation,labeling,computer-vision,dataset,mlops,sdk,mcp
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ License-File: NOTICE
27
+ Requires-Dist: httpx>=0.27
28
+ Provides-Extra: mcp
29
+ Requires-Dist: mcp<3,>=2.2; extra == "mcp"
30
+ Provides-Extra: dev
31
+ Requires-Dist: mcp<3,>=2.2; extra == "dev"
32
+ Requires-Dist: pytest>=8.3; extra == "dev"
33
+ Requires-Dist: ruff>=0.8; extra == "dev"
34
+ Requires-Dist: mypy>=1.13; extra == "dev"
35
+ Requires-Dist: datamodel-code-generator>=0.83; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # annotide
39
+
40
+ Python SDK and command line for the Annotide API (API-3). One
41
+ runtime dependency (`httpx`); responses are plain dicts typed with
42
+ `TypedDict`s generated from the API's OpenAPI document.
43
+
44
+ ```sh
45
+ pip install annotide # or `pip install -e sdk` from a checkout
46
+ export ANNOTIDE_URL=https://annotate.example.com
47
+ export ANNOTIDE_API_KEY=... # Settings → API keys; use a service account for CI
48
+ ```
49
+
50
+ ## Python
51
+
52
+ ```python
53
+ from annotide import Client, JobFailedError
54
+
55
+ with Client() as client: # reads ANNOTIDE_URL / ANNOTIDE_API_KEY
56
+ project = next(p for p in client.list_projects() if p["name"] == "Cars")
57
+
58
+ # Freeze the dataset, then export it reproducibly.
59
+ snapshot = client.take_snapshot(
60
+ project["id"],
61
+ "2026-q3",
62
+ split={"train": 0.8, "val": 0.1, "test": 0.1, "seed": 0, "group_by": "folder"},
63
+ )
64
+ client.export(project["id"], "coco", "train.zip", snapshot_id=snapshot["id"], split="train")
65
+
66
+ # Import existing labels; a dry run reports what would happen.
67
+ report = client.import_file(project["id"], "labels.json", "coco", dry_run=True)
68
+ print(report["result"])
69
+ ```
70
+
71
+ - Errors are `ApiError` (`status`, `title`, `detail` from the RFC 9457
72
+ body); a job that ends `failed`/`cancelled` raises `JobFailedError`, one
73
+ that outlives its `timeout` raises `JobTimeoutError`.
74
+ - A 429 waits for `Retry-After` and repeats. Gateway errors (502/503/504)
75
+ repeat only when that is harmless: reads, and creates, which always carry
76
+ an `Idempotency-Key` so a repeat answers the first row.
77
+ - Export downloads go straight to storage with the signed URL; the API key
78
+ is never sent there.
79
+ - `client.request(method, path, ...)` reaches any endpoint without a method.
80
+
81
+ ## Command line
82
+
83
+ ```sh
84
+ annotide whoami
85
+ annotide projects list | jq -r '.name'
86
+ annotide snapshots create <project> 2026-q3 --split 0.8,0.1,0.1 --group-by folder
87
+ annotide export <project> --format coco --snapshot <id> --split train -o train.zip
88
+ annotide import <project> labels.json --format coco --class-map '{"auto": "car"}' --dry-run
89
+ annotide jobs wait <job>
90
+ ```
91
+
92
+ Lists print as JSON Lines, single objects as JSON; errors go to stderr with
93
+ exit status 1. The key is read from `ANNOTIDE_API_KEY` only, so it never
94
+ lands in shell history.
95
+
96
+ ## MCP server for AI agents (API-8)
97
+
98
+ `annotide mcp` serves the [Model Context Protocol](https://modelcontextprotocol.io)
99
+ over stdio, so an AI agent (Claude Code, Claude Desktop, or any MCP client)
100
+ can pre-label a project. It calls the REST API with an API key, so the agent
101
+ can do exactly what that account may do. It can list projects and their label
102
+ schema, view items (images come back as images), read annotations, claim and
103
+ release tasks, and post pre-labels. It cannot submit, review, delete or
104
+ export.
105
+
106
+ Setup, once per agent:
107
+
108
+ 1. **Service account.** Settings → API keys → Service accounts: create one,
109
+ mint a `write` key, and add the account to the project as an annotator.
110
+ 2. **Model.** Models → Register model, name it after the agent, and leave
111
+ the endpoint empty. That makes it an *external producer*: the platform
112
+ never calls it, and the agent posts the pre-labels. Add version 1 and
113
+ note its id.
114
+ 3. **Client config.** For Claude Code (`.mcp.json`) or Claude Desktop:
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "annotation": {
120
+ "command": "annotation",
121
+ "args": ["mcp"],
122
+ "env": {
123
+ "ANNOTIDE_URL": "https://annotate.example.com",
124
+ "ANNOTIDE_API_KEY": "ak_…",
125
+ "ANNOTIDE_MODEL_VERSION_ID": "<model version id>"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ Install with `pip install "annotide[mcp]"`. Pre-labels arrive as
133
+ `draft` versions authored by the model version. People review and submit
134
+ them as usual, and a pre-label never replaces human work (ML-10).
135
+
136
+ ## Development
137
+
138
+ ```sh
139
+ make install # from the repository root: creates sdk/.venv
140
+ cd sdk && .venv/bin/pytest && .venv/bin/mypy annotide tests tools
141
+ make openapi # after an API change: docs/openapi.json + models.py
142
+ ```
143
+
144
+ `annotide/models.py` is generated; never edit it by hand. CI fails when
145
+ it or `docs/openapi.json` is stale.
@@ -1,11 +1,27 @@
1
1
  [project]
2
2
  name = "annotide"
3
- version = "0.1.0"
4
- description = "Cloud-agnostic annotation platform — Python SDK and CLI (API-3)"
3
+ version = "0.1.2"
4
+ description = "Python SDK, CLI and MCP server for the Annotide annotation platform"
5
+ readme = "README.md"
5
6
  requires-python = ">=3.12"
6
7
  # The SDK is Apache-2.0; the server it talks to is ELv2 (LICENSE.md at the repo root).
7
8
  license = "Apache-2.0"
8
9
  license-files = ["LICENSE", "NOTICE"]
10
+ authors = [{ name = "Annotide" }]
11
+ keywords = ["annotation", "labeling", "computer-vision", "dataset", "mlops", "sdk", "mcp"]
12
+ # No `License ::` classifiers: PEP 639 `license` expressions replace them.
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "Intended Audience :: Science/Research",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ "Topic :: Scientific/Engineering :: Image Recognition",
23
+ "Typing :: Typed",
24
+ ]
9
25
  # One runtime dependency. Models are TypedDicts (plain dicts at runtime), so
10
26
  # the SDK never pins pydantic against a customer's ML environment.
11
27
  dependencies = [
@@ -26,6 +42,13 @@ dev = [
26
42
  "datamodel-code-generator>=0.83",
27
43
  ]
28
44
 
45
+ [project.urls]
46
+ Homepage = "https://annotide.com"
47
+ Documentation = "https://github.com/annotide/annotide/tree/main/sdk#readme"
48
+ Source = "https://github.com/annotide/annotide/tree/main/sdk"
49
+ Issues = "https://github.com/annotide/annotide/issues"
50
+ Changelog = "https://github.com/annotide/annotide/releases"
51
+
29
52
  [project.scripts]
30
53
  annotide = "annotide.cli:main"
31
54
 
annotide-0.1.0/PKG-INFO DELETED
@@ -1,18 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: annotide
3
- Version: 0.1.0
4
- Summary: Cloud-agnostic annotation platform — Python SDK and CLI (API-3)
5
- License-Expression: Apache-2.0
6
- Requires-Python: >=3.12
7
- License-File: LICENSE
8
- License-File: NOTICE
9
- Requires-Dist: httpx>=0.27
10
- Provides-Extra: mcp
11
- Requires-Dist: mcp<3,>=2.2; extra == "mcp"
12
- Provides-Extra: dev
13
- Requires-Dist: mcp<3,>=2.2; extra == "dev"
14
- Requires-Dist: pytest>=8.3; extra == "dev"
15
- Requires-Dist: ruff>=0.8; extra == "dev"
16
- Requires-Dist: mypy>=1.13; extra == "dev"
17
- Requires-Dist: datamodel-code-generator>=0.83; extra == "dev"
18
- Dynamic: license-file
@@ -1,18 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: annotide
3
- Version: 0.1.0
4
- Summary: Cloud-agnostic annotation platform — Python SDK and CLI (API-3)
5
- License-Expression: Apache-2.0
6
- Requires-Python: >=3.12
7
- License-File: LICENSE
8
- License-File: NOTICE
9
- Requires-Dist: httpx>=0.27
10
- Provides-Extra: mcp
11
- Requires-Dist: mcp<3,>=2.2; extra == "mcp"
12
- Provides-Extra: dev
13
- Requires-Dist: mcp<3,>=2.2; extra == "dev"
14
- Requires-Dist: pytest>=8.3; extra == "dev"
15
- Requires-Dist: ruff>=0.8; extra == "dev"
16
- Requires-Dist: mypy>=1.13; extra == "dev"
17
- Requires-Dist: datamodel-code-generator>=0.83; extra == "dev"
18
- Dynamic: license-file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes