gravity-schema 0.4.4__tar.gz → 0.5.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.
Files changed (30) hide show
  1. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/PKG-INFO +1 -1
  2. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/__init__.py +6 -0
  3. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/catalog.py +11 -2
  4. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/catalog.yaml +45 -0
  5. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/catalog_imported.yaml +9632 -4276
  6. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/errors.py +2 -0
  7. gravity_schema-0.5.2/gravity_schema/source_scan.py +83 -0
  8. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/validation.py +23 -2
  9. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/pyproject.toml +1 -1
  10. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_catalog_parity.py +11 -0
  11. gravity_schema-0.5.2/tests/test_source_scan.py +67 -0
  12. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_validation.py +25 -0
  13. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/.gitignore +0 -0
  14. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/LICENSE +0 -0
  15. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/NOTICE +0 -0
  16. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/README.md +0 -0
  17. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/__main__.py +0 -0
  18. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/contract.py +0 -0
  19. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/cron.py +0 -0
  20. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/export.py +0 -0
  21. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/gen_catalog.py +0 -0
  22. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/gravity_schema/manifest.py +0 -0
  23. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/schema/manifest.schema.json +0 -0
  24. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/conftest.py +0 -0
  25. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_cron.py +0 -0
  26. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_errors.py +0 -0
  27. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_json_schema.py +0 -0
  28. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_kind_outputs.py +0 -0
  29. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_manifest.py +0 -0
  30. {gravity_schema-0.4.4 → gravity_schema-0.5.2}/tests/test_slots.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: gravity-schema
3
- Version: 0.4.4
3
+ Version: 0.5.2
4
4
  Summary: Gravity agent manifest contract — models, validation, and JSON Schema export
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -36,7 +36,9 @@ from .manifest import (
36
36
  StateSpec,
37
37
  TriggersSpec,
38
38
  )
39
+ from .source_scan import is_agent_source, undeclared_write_tools
39
40
  from .validation import (
41
+ check_imported_write_approvals,
40
42
  check_tool_references,
41
43
  load_manifest_file,
42
44
  load_manifest_text,
@@ -73,6 +75,10 @@ __all__ = [ # noqa: RUF022 - grouped by concern, not alphabetical
73
75
  "load_manifest_text",
74
76
  "load_manifest_file",
75
77
  "check_tool_references",
78
+ "check_imported_write_approvals",
79
+ # source scan
80
+ "is_agent_source",
81
+ "undeclared_write_tools",
76
82
  # catalog
77
83
  "ToolCatalog",
78
84
  "StaticToolCatalog",
@@ -10,6 +10,13 @@ from typing import Protocol
10
10
 
11
11
  import yaml
12
12
 
13
+ # libyaml's parser, about 8x faster: every CLI command loads the whole catalog at import.
14
+ _LOADER = getattr(yaml, "CSafeLoader", yaml.SafeLoader)
15
+
16
+
17
+ def _load(text: str):
18
+ return yaml.load(text, Loader=_LOADER)
19
+
13
20
 
14
21
  class ToolCatalog(Protocol):
15
22
  def exists(self, tool_name: str) -> bool: ...
@@ -39,6 +46,7 @@ class ToolEntry:
39
46
  breadth: str # generic | niche
40
47
  guarantee: str # certified | community | experimental
41
48
  side_effect: str # read | write
49
+ toolkit: str | None = None # the account a user connects for it; None when none is needed
42
50
 
43
51
 
44
52
  _BREADTH = {"generic", "niche"}
@@ -48,12 +56,12 @@ _SIDE_EFFECT = {"read", "write"}
48
56
 
49
57
  def load_catalog(path: Path | None = None) -> tuple[ToolEntry, ...]:
50
58
  """Parse and check catalog.yaml; a malformed entry fails at import."""
51
- raw = yaml.safe_load((path or Path(__file__).with_name("catalog.yaml")).read_text(encoding="utf-8"))
59
+ raw = _load((path or Path(__file__).with_name("catalog.yaml")).read_text(encoding="utf-8"))
52
60
  # catalog_imported.yaml (`gravity-gateway sync-tools`): the same apps' other tools,
53
61
  # experimental. Absent until the first sync; never read for an explicit path.
54
62
  imported = Path(__file__).with_name("catalog_imported.yaml")
55
63
  if path is None and imported.is_file():
56
- raw = [*raw, *(yaml.safe_load(imported.read_text(encoding="utf-8")) or [])]
64
+ raw = [*raw, *(_load(imported.read_text(encoding="utf-8")) or [])]
57
65
  entries: list[ToolEntry] = []
58
66
  for item in raw:
59
67
  entry = ToolEntry(
@@ -64,6 +72,7 @@ def load_catalog(path: Path | None = None) -> tuple[ToolEntry, ...]:
64
72
  breadth=item["breadth"],
65
73
  guarantee=item["guarantee"],
66
74
  side_effect=item["side_effect"],
75
+ toolkit=item.get("toolkit"),
67
76
  )
68
77
  problems = []
69
78
  if entry.breadth not in _BREADTH:
@@ -10,6 +10,7 @@
10
10
  # Fields
11
11
  # name the Gravity name builders write in permissions.tools
12
12
  # slug the vendor action it routes to; null for a gateway built-in
13
+ # toolkit the account a user connects for it (gravity connect); null when none is needed
13
14
  # description what a builder or a model reads to choose it
14
15
  # scopes the consent a consumer grants when connecting
15
16
  # breadth generic: ordinary plumbing any agent might use
@@ -21,14 +22,34 @@
21
22
 
22
23
  - name: example.echo
23
24
  slug: null
25
+ toolkit: null
24
26
  description: echoes back its input, for templates and plumbing tests
25
27
  scopes: []
26
28
  breadth: generic
27
29
  guarantee: certified
28
30
  side_effect: read
29
31
 
32
+ - name: web.search
33
+ slug: COMPOSIO_SEARCH_WEB
34
+ toolkit: composio_search
35
+ description: search the web; returns results with titles, links and snippets. No account needed
36
+ scopes: []
37
+ breadth: generic
38
+ guarantee: certified
39
+ side_effect: read
40
+
41
+ - name: web.fetch
42
+ slug: COMPOSIO_SEARCH_FETCH_URL_CONTENT
43
+ toolkit: composio_search
44
+ description: read the text content of a web page by its URL. No account needed
45
+ scopes: []
46
+ breadth: generic
47
+ guarantee: certified
48
+ side_effect: read
49
+
30
50
  - name: supadata.get_transcript
31
51
  slug: null
52
+ toolkit: null
32
53
  description: fetch the transcript of a YouTube video with the caller's own Supadata API key (api_key argument)
33
54
  scopes: []
34
55
  breadth: niche
@@ -37,6 +58,7 @@
37
58
 
38
59
  - name: gmail.read
39
60
  slug: GMAIL_FETCH_EMAILS
61
+ toolkit: gmail
40
62
  description: read the connected Gmail inbox
41
63
  scopes: [gmail.readonly]
42
64
  breadth: generic
@@ -45,6 +67,7 @@
45
67
 
46
68
  - name: gmail.draft
47
69
  slug: GMAIL_CREATE_EMAIL_DRAFT
70
+ toolkit: gmail
48
71
  description: create a Gmail draft
49
72
  scopes: [gmail.compose]
50
73
  breadth: generic
@@ -53,6 +76,7 @@
53
76
 
54
77
  - name: gmail.send
55
78
  slug: GMAIL_SEND_EMAIL
79
+ toolkit: gmail
56
80
  description: send an email from the connected Gmail
57
81
  scopes: [gmail.send]
58
82
  breadth: generic
@@ -61,6 +85,7 @@
61
85
 
62
86
  - name: sheets.read
63
87
  slug: GOOGLESHEETS_BATCH_GET
88
+ toolkit: googlesheets
64
89
  description: read values from a connected Google Sheet
65
90
  scopes: [sheets]
66
91
  breadth: generic
@@ -69,6 +94,7 @@
69
94
 
70
95
  - name: sheets.append
71
96
  slug: GOOGLESHEETS_BATCH_UPDATE
97
+ toolkit: googlesheets
72
98
  description: append a row to a connected Google Sheet
73
99
  scopes: [sheets]
74
100
  breadth: generic
@@ -77,6 +103,7 @@
77
103
 
78
104
  - name: slack.send
79
105
  slug: SLACK_SEND_MESSAGE
106
+ toolkit: slack
80
107
  description: post a message to a connected Slack channel
81
108
  scopes: [slack.chat:write]
82
109
  breadth: generic
@@ -85,6 +112,7 @@
85
112
 
86
113
  - name: slack.list_channels
87
114
  slug: SLACK_LIST_ALL_CHANNELS
115
+ toolkit: slack
88
116
  description: list channels in the connected Slack workspace
89
117
  scopes: [slack.channels:read]
90
118
  breadth: generic
@@ -93,6 +121,7 @@
93
121
 
94
122
  - name: slack.read_history
95
123
  slug: SLACK_FETCH_CONVERSATION_HISTORY
124
+ toolkit: slack
96
125
  description: read message history of a Slack channel
97
126
  scopes: [slack.channels:history]
98
127
  breadth: generic
@@ -101,6 +130,7 @@
101
130
 
102
131
  - name: slack.find_user
103
132
  slug: SLACK_FIND_USERS
133
+ toolkit: slack
104
134
  description: find a Slack user by name, handle or email, for mentions
105
135
  scopes: [slack.users:read]
106
136
  breadth: generic
@@ -109,6 +139,7 @@
109
139
 
110
140
  - name: calendar.read
111
141
  slug: GOOGLECALENDAR_EVENTS_LIST
142
+ toolkit: googlecalendar
112
143
  description: list events on the connected Google Calendar
113
144
  scopes: [calendar.readonly]
114
145
  breadth: generic
@@ -117,6 +148,7 @@
117
148
 
118
149
  - name: drive.read
119
150
  slug: GOOGLEDRIVE_DOWNLOAD_FILE
151
+ toolkit: googledrive
120
152
  description: download a file from the connected Google Drive
121
153
  scopes: [drive.readonly]
122
154
  breadth: generic
@@ -125,6 +157,7 @@
125
157
 
126
158
  - name: linear.create_issue
127
159
  slug: LINEAR_CREATE_LINEAR_ISSUE
160
+ toolkit: linear
128
161
  description: create an issue in a connected Linear team
129
162
  scopes: [linear.write]
130
163
  breadth: generic
@@ -133,6 +166,7 @@
133
166
 
134
167
  - name: linear.list_teams
135
168
  slug: LINEAR_LIST_LINEAR_TEAMS
169
+ toolkit: linear
136
170
  description: list the connected Linear workspace teams
137
171
  scopes: [linear.read]
138
172
  breadth: generic
@@ -141,6 +175,7 @@
141
175
 
142
176
  - name: linear.list_issues
143
177
  slug: LINEAR_LIST_LINEAR_ISSUES
178
+ toolkit: linear
144
179
  description: list open issues in the connected Linear workspace
145
180
  scopes: [linear.read]
146
181
  breadth: generic
@@ -149,6 +184,7 @@
149
184
 
150
185
  - name: linear.get_issue
151
186
  slug: LINEAR_GET_LINEAR_ISSUE
187
+ toolkit: linear
152
188
  description: read one Linear issue by id
153
189
  scopes: [linear.read]
154
190
  breadth: generic
@@ -158,6 +194,7 @@
158
194
  # GitHub: read-only, for change summaries and contribution profiles.
159
195
  - name: github.list_commits
160
196
  slug: GITHUB_LIST_COMMITS
197
+ toolkit: github
161
198
  description: list commits on a repository branch, filterable by date range, author or path
162
199
  scopes: [repo]
163
200
  breadth: generic
@@ -166,6 +203,7 @@
166
203
 
167
204
  - name: github.get_commit
168
205
  slug: GITHUB_GET_A_COMMIT
206
+ toolkit: github
169
207
  description: read one commit with its changed files, line counts and patches
170
208
  scopes: [repo]
171
209
  breadth: generic
@@ -174,6 +212,7 @@
174
212
 
175
213
  - name: github.compare
176
214
  slug: GITHUB_COMPARE_TWO_COMMITS
215
+ toolkit: github
177
216
  description: compare two refs (base...head) with the commits and changed files between them
178
217
  scopes: [repo]
179
218
  breadth: generic
@@ -182,6 +221,7 @@
182
221
 
183
222
  - name: github.list_pull_requests
184
223
  slug: GITHUB_LIST_PULL_REQUESTS
224
+ toolkit: github
185
225
  description: list pull requests on a repository, filterable by state and branch
186
226
  scopes: [repo]
187
227
  breadth: generic
@@ -190,6 +230,7 @@
190
230
 
191
231
  - name: github.list_pr_files
192
232
  slug: GITHUB_LIST_PULL_REQUESTS_FILES
233
+ toolkit: github
193
234
  description: list the files a pull request changes, with line counts and patches
194
235
  scopes: [repo]
195
236
  breadth: generic
@@ -198,6 +239,7 @@
198
239
 
199
240
  - name: github.list_pr_reviews
200
241
  slug: GITHUB_LIST_REVIEWS_FOR_A_PULL_REQUEST
242
+ toolkit: github
201
243
  description: list the reviews submitted on a pull request
202
244
  scopes: [repo]
203
245
  breadth: generic
@@ -206,6 +248,7 @@
206
248
 
207
249
  - name: github.search_issues
208
250
  slug: GITHUB_SEARCH_ISSUES_AND_PULL_REQUESTS
251
+ toolkit: github
209
252
  description: search issues and pull requests with GitHub qualifiers (repo:, author:, reviewed-by:, is:pr, created:)
210
253
  scopes: [repo]
211
254
  breadth: generic
@@ -214,6 +257,7 @@
214
257
 
215
258
  - name: linkedin.whoami
216
259
  slug: LINKEDIN_GET_MY_INFO
260
+ toolkit: linkedin
217
261
  description: read the connected LinkedIn member's id, name and headline (the author of their posts)
218
262
  scopes: [linkedin.profile]
219
263
  breadth: generic
@@ -222,6 +266,7 @@
222
266
 
223
267
  - name: linkedin.create_post
224
268
  slug: LINKEDIN_CREATE_LINKED_IN_POST
269
+ toolkit: linkedin
225
270
  description: publish a post on LinkedIn as the connected member or an organisation they manage
226
271
  scopes: [linkedin.w_member_social]
227
272
  breadth: generic