dwclaw-cli 1.0.0

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,763 @@
1
+ ---
2
+ name: github
3
+ description: |
4
+ GitHub API integration with managed OAuth. Access repositories, issues, pull requests, commits, branches, and users.
5
+ Use this skill when users want to interact with GitHub repositories, manage issues and PRs, search code, or automate workflows.
6
+ For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
7
+ compatibility: Requires network access and valid Maton API key
8
+ metadata:
9
+ author: maton
10
+ version: "1.0"
11
+ clawdbot:
12
+ emoji: 🧠
13
+ requires:
14
+ env:
15
+ - MATON_API_KEY
16
+ ---
17
+
18
+ # GitHub
19
+
20
+ Access the GitHub REST API with managed OAuth authentication. Manage repositories, issues, pull requests, commits, branches, users, and more.
21
+
22
+ ## Quick Start
23
+
24
+ ```bash
25
+ # Get authenticated user
26
+ python <<'EOF'
27
+ import urllib.request, os, json
28
+ req = urllib.request.Request('https://gateway.maton.ai/github/user')
29
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
30
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
31
+ EOF
32
+ ```
33
+
34
+ ## Base URL
35
+
36
+ ```
37
+ https://gateway.maton.ai/github/{native-api-path}
38
+ ```
39
+
40
+ Replace `{native-api-path}` with the actual GitHub API endpoint path. The gateway proxies requests to `api.github.com` and automatically injects your OAuth token.
41
+
42
+ ## Authentication
43
+
44
+ All requests require the Maton API key in the Authorization header:
45
+
46
+ ```
47
+ Authorization: Bearer $MATON_API_KEY
48
+ ```
49
+
50
+ **Environment Variable:** Set your API key as `MATON_API_KEY`:
51
+
52
+ ```bash
53
+ export MATON_API_KEY="YOUR_API_KEY"
54
+ ```
55
+
56
+ ### Getting Your API Key
57
+
58
+ 1. Sign in or create an account at [maton.ai](https://maton.ai)
59
+ 2. Go to [maton.ai/settings](https://maton.ai/settings)
60
+ 3. Copy your API key
61
+
62
+ ## Connection Management
63
+
64
+ Manage your GitHub OAuth connections at `https://ctrl.maton.ai`.
65
+
66
+ ### List Connections
67
+
68
+ ```bash
69
+ python <<'EOF'
70
+ import urllib.request, os, json
71
+ req = urllib.request.Request('https://ctrl.maton.ai/connections?app=github&status=ACTIVE')
72
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
73
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
74
+ EOF
75
+ ```
76
+
77
+ ### Create Connection
78
+
79
+ ```bash
80
+ python <<'EOF'
81
+ import urllib.request, os, json
82
+ data = json.dumps({'app': 'github'}).encode()
83
+ req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
84
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
85
+ req.add_header('Content-Type', 'application/json')
86
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
87
+ EOF
88
+ ```
89
+
90
+ ### Get Connection
91
+
92
+ ```bash
93
+ python <<'EOF'
94
+ import urllib.request, os, json
95
+ req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
96
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
97
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
98
+ EOF
99
+ ```
100
+
101
+ **Response:**
102
+ ```json
103
+ {
104
+ "connection": {
105
+ "connection_id": "83e7c665-60f6-4a64-816c-5e287ea8982f",
106
+ "status": "ACTIVE",
107
+ "creation_time": "2026-02-06T03:00:43.860014Z",
108
+ "last_updated_time": "2026-02-06T03:01:06.027323Z",
109
+ "url": "https://connect.maton.ai/?session_token=...",
110
+ "app": "github",
111
+ "metadata": {}
112
+ }
113
+ }
114
+ ```
115
+
116
+ Open the returned `url` in a browser to complete OAuth authorization.
117
+
118
+ ### Delete Connection
119
+
120
+ ```bash
121
+ python <<'EOF'
122
+ import urllib.request, os, json
123
+ req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
124
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
125
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
126
+ EOF
127
+ ```
128
+
129
+ ### Specifying Connection
130
+
131
+ If you have multiple GitHub connections, specify which one to use with the `Maton-Connection` header:
132
+
133
+ ```bash
134
+ python <<'EOF'
135
+ import urllib.request, os, json
136
+ req = urllib.request.Request('https://gateway.maton.ai/github/user')
137
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
138
+ req.add_header('Maton-Connection', '83e7c665-60f6-4a64-816c-5e287ea8982f')
139
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
140
+ EOF
141
+ ```
142
+
143
+ If omitted, the gateway uses the default (oldest) active connection.
144
+
145
+ ## API Reference
146
+
147
+ ### Users
148
+
149
+ #### Get Authenticated User
150
+
151
+ ```bash
152
+ GET /github/user
153
+ ```
154
+
155
+ #### Get User by Username
156
+
157
+ ```bash
158
+ GET /github/users/{username}
159
+ ```
160
+
161
+ #### List Users
162
+
163
+ ```bash
164
+ GET /github/users?since={user_id}&per_page=30
165
+ ```
166
+
167
+ ### Repositories
168
+
169
+ #### List User Repositories
170
+
171
+ ```bash
172
+ GET /github/user/repos?per_page=30&sort=updated
173
+ ```
174
+
175
+ Query parameters: `type` (all, owner, public, private, member), `sort` (created, updated, pushed, full_name), `direction` (asc, desc), `per_page`, `page`
176
+
177
+ #### List Organization Repositories
178
+
179
+ ```bash
180
+ GET /github/orgs/{org}/repos?per_page=30
181
+ ```
182
+
183
+ #### Get Repository
184
+
185
+ ```bash
186
+ GET /github/repos/{owner}/{repo}
187
+ ```
188
+
189
+ #### Create Repository (User)
190
+
191
+ ```bash
192
+ POST /github/user/repos
193
+ Content-Type: application/json
194
+
195
+ {
196
+ "name": "my-new-repo",
197
+ "description": "A new repository",
198
+ "private": true,
199
+ "auto_init": true
200
+ }
201
+ ```
202
+
203
+ #### Create Repository (Organization)
204
+
205
+ ```bash
206
+ POST /github/orgs/{org}/repos
207
+ Content-Type: application/json
208
+
209
+ {
210
+ "name": "my-new-repo",
211
+ "description": "A new repository",
212
+ "private": true
213
+ }
214
+ ```
215
+
216
+ #### Update Repository
217
+
218
+ ```bash
219
+ PATCH /github/repos/{owner}/{repo}
220
+ Content-Type: application/json
221
+
222
+ {
223
+ "description": "Updated description",
224
+ "has_issues": true,
225
+ "has_wiki": false
226
+ }
227
+ ```
228
+
229
+ #### Delete Repository
230
+
231
+ ```bash
232
+ DELETE /github/repos/{owner}/{repo}
233
+ ```
234
+
235
+ ### Repository Contents
236
+
237
+ #### List Contents
238
+
239
+ ```bash
240
+ GET /github/repos/{owner}/{repo}/contents/{path}
241
+ ```
242
+
243
+ #### Get File Contents
244
+
245
+ ```bash
246
+ GET /github/repos/{owner}/{repo}/contents/{path}?ref={branch}
247
+ ```
248
+
249
+ #### Create or Update File
250
+
251
+ ```bash
252
+ PUT /github/repos/{owner}/{repo}/contents/{path}
253
+ Content-Type: application/json
254
+
255
+ {
256
+ "message": "Create new file",
257
+ "content": "SGVsbG8gV29ybGQh",
258
+ "branch": "main"
259
+ }
260
+ ```
261
+
262
+ Note: `content` must be Base64 encoded.
263
+
264
+ #### Delete File
265
+
266
+ ```bash
267
+ DELETE /github/repos/{owner}/{repo}/contents/{path}
268
+ Content-Type: application/json
269
+
270
+ {
271
+ "message": "Delete file",
272
+ "sha": "{file_sha}",
273
+ "branch": "main"
274
+ }
275
+ ```
276
+
277
+ ### Branches
278
+
279
+ #### List Branches
280
+
281
+ ```bash
282
+ GET /github/repos/{owner}/{repo}/branches?per_page=30
283
+ ```
284
+
285
+ #### Get Branch
286
+
287
+ ```bash
288
+ GET /github/repos/{owner}/{repo}/branches/{branch}
289
+ ```
290
+
291
+ #### Rename Branch
292
+
293
+ ```bash
294
+ POST /github/repos/{owner}/{repo}/branches/{branch}/rename
295
+ Content-Type: application/json
296
+
297
+ {
298
+ "new_name": "new-branch-name"
299
+ }
300
+ ```
301
+
302
+ #### Merge Branches
303
+
304
+ ```bash
305
+ POST /github/repos/{owner}/{repo}/merges
306
+ Content-Type: application/json
307
+
308
+ {
309
+ "base": "main",
310
+ "head": "feature-branch",
311
+ "commit_message": "Merge feature branch"
312
+ }
313
+ ```
314
+
315
+ ### Commits
316
+
317
+ #### List Commits
318
+
319
+ ```bash
320
+ GET /github/repos/{owner}/{repo}/commits?per_page=30
321
+ ```
322
+
323
+ Query parameters: `sha` (branch name or commit SHA), `path` (file path), `author`, `committer`, `since`, `until`, `per_page`, `page`
324
+
325
+ #### Get Commit
326
+
327
+ ```bash
328
+ GET /github/repos/{owner}/{repo}/commits/{ref}
329
+ ```
330
+
331
+ #### Compare Two Commits
332
+
333
+ ```bash
334
+ GET /github/repos/{owner}/{repo}/compare/{base}...{head}
335
+ ```
336
+
337
+ ### Issues
338
+
339
+ #### List Repository Issues
340
+
341
+ ```bash
342
+ GET /github/repos/{owner}/{repo}/issues?state=open&per_page=30
343
+ ```
344
+
345
+ Query parameters: `state` (open, closed, all), `labels`, `assignee`, `creator`, `mentioned`, `sort`, `direction`, `since`, `per_page`, `page`
346
+
347
+ #### Get Issue
348
+
349
+ ```bash
350
+ GET /github/repos/{owner}/{repo}/issues/{issue_number}
351
+ ```
352
+
353
+ #### Create Issue
354
+
355
+ ```bash
356
+ POST /github/repos/{owner}/{repo}/issues
357
+ Content-Type: application/json
358
+
359
+ {
360
+ "title": "Found a bug",
361
+ "body": "Bug description here",
362
+ "labels": ["bug"],
363
+ "assignees": ["username"]
364
+ }
365
+ ```
366
+
367
+ #### Update Issue
368
+
369
+ ```bash
370
+ PATCH /github/repos/{owner}/{repo}/issues/{issue_number}
371
+ Content-Type: application/json
372
+
373
+ {
374
+ "state": "closed",
375
+ "state_reason": "completed"
376
+ }
377
+ ```
378
+
379
+ #### Lock Issue
380
+
381
+ ```bash
382
+ PUT /github/repos/{owner}/{repo}/issues/{issue_number}/lock
383
+ Content-Type: application/json
384
+
385
+ {
386
+ "lock_reason": "resolved"
387
+ }
388
+ ```
389
+
390
+ #### Unlock Issue
391
+
392
+ ```bash
393
+ DELETE /github/repos/{owner}/{repo}/issues/{issue_number}/lock
394
+ ```
395
+
396
+ ### Issue Comments
397
+
398
+ #### List Issue Comments
399
+
400
+ ```bash
401
+ GET /github/repos/{owner}/{repo}/issues/{issue_number}/comments?per_page=30
402
+ ```
403
+
404
+ #### Create Issue Comment
405
+
406
+ ```bash
407
+ POST /github/repos/{owner}/{repo}/issues/{issue_number}/comments
408
+ Content-Type: application/json
409
+
410
+ {
411
+ "body": "This is a comment"
412
+ }
413
+ ```
414
+
415
+ #### Update Issue Comment
416
+
417
+ ```bash
418
+ PATCH /github/repos/{owner}/{repo}/issues/comments/{comment_id}
419
+ Content-Type: application/json
420
+
421
+ {
422
+ "body": "Updated comment"
423
+ }
424
+ ```
425
+
426
+ #### Delete Issue Comment
427
+
428
+ ```bash
429
+ DELETE /github/repos/{owner}/{repo}/issues/comments/{comment_id}
430
+ ```
431
+
432
+ ### Labels
433
+
434
+ #### List Labels
435
+
436
+ ```bash
437
+ GET /github/repos/{owner}/{repo}/labels?per_page=30
438
+ ```
439
+
440
+ #### Create Label
441
+
442
+ ```bash
443
+ POST /github/repos/{owner}/{repo}/labels
444
+ Content-Type: application/json
445
+
446
+ {
447
+ "name": "priority:high",
448
+ "color": "ff0000",
449
+ "description": "High priority issues"
450
+ }
451
+ ```
452
+
453
+ ### Milestones
454
+
455
+ #### List Milestones
456
+
457
+ ```bash
458
+ GET /github/repos/{owner}/{repo}/milestones?state=open&per_page=30
459
+ ```
460
+
461
+ #### Create Milestone
462
+
463
+ ```bash
464
+ POST /github/repos/{owner}/{repo}/milestones
465
+ Content-Type: application/json
466
+
467
+ {
468
+ "title": "v1.0",
469
+ "state": "open",
470
+ "description": "First release",
471
+ "due_on": "2026-03-01T00:00:00Z"
472
+ }
473
+ ```
474
+
475
+ ### Pull Requests
476
+
477
+ #### List Pull Requests
478
+
479
+ ```bash
480
+ GET /github/repos/{owner}/{repo}/pulls?state=open&per_page=30
481
+ ```
482
+
483
+ Query parameters: `state` (open, closed, all), `head`, `base`, `sort`, `direction`, `per_page`, `page`
484
+
485
+ #### Get Pull Request
486
+
487
+ ```bash
488
+ GET /github/repos/{owner}/{repo}/pulls/{pull_number}
489
+ ```
490
+
491
+ #### Create Pull Request
492
+
493
+ ```bash
494
+ POST /github/repos/{owner}/{repo}/pulls
495
+ Content-Type: application/json
496
+
497
+ {
498
+ "title": "New feature",
499
+ "body": "Description of changes",
500
+ "head": "feature-branch",
501
+ "base": "main",
502
+ "draft": false
503
+ }
504
+ ```
505
+
506
+ #### Update Pull Request
507
+
508
+ ```bash
509
+ PATCH /github/repos/{owner}/{repo}/pulls/{pull_number}
510
+ Content-Type: application/json
511
+
512
+ {
513
+ "title": "Updated title",
514
+ "state": "closed"
515
+ }
516
+ ```
517
+
518
+ #### List Pull Request Commits
519
+
520
+ ```bash
521
+ GET /github/repos/{owner}/{repo}/pulls/{pull_number}/commits?per_page=30
522
+ ```
523
+
524
+ #### List Pull Request Files
525
+
526
+ ```bash
527
+ GET /github/repos/{owner}/{repo}/pulls/{pull_number}/files?per_page=30
528
+ ```
529
+
530
+ #### Check If Merged
531
+
532
+ ```bash
533
+ GET /github/repos/{owner}/{repo}/pulls/{pull_number}/merge
534
+ ```
535
+
536
+ #### Merge Pull Request
537
+
538
+ ```bash
539
+ PUT /github/repos/{owner}/{repo}/pulls/{pull_number}/merge
540
+ Content-Type: application/json
541
+
542
+ {
543
+ "commit_title": "Merge pull request",
544
+ "merge_method": "squash"
545
+ }
546
+ ```
547
+
548
+ Merge methods: `merge`, `squash`, `rebase`
549
+
550
+ ### Pull Request Reviews
551
+
552
+ #### List Reviews
553
+
554
+ ```bash
555
+ GET /github/repos/{owner}/{repo}/pulls/{pull_number}/reviews?per_page=30
556
+ ```
557
+
558
+ #### Create Review
559
+
560
+ ```bash
561
+ POST /github/repos/{owner}/{repo}/pulls/{pull_number}/reviews
562
+ Content-Type: application/json
563
+
564
+ {
565
+ "body": "Looks good!",
566
+ "event": "APPROVE"
567
+ }
568
+ ```
569
+
570
+ Events: `APPROVE`, `REQUEST_CHANGES`, `COMMENT`
571
+
572
+ ### Search
573
+
574
+ #### Search Repositories
575
+
576
+ ```bash
577
+ GET /github/search/repositories?q={query}&per_page=30
578
+ ```
579
+
580
+ Example queries:
581
+ - `tetris+language:python` - Repositories with "tetris" in Python
582
+ - `react+stars:>10000` - Repositories with "react" and 10k+ stars
583
+
584
+ #### Search Issues
585
+
586
+ ```bash
587
+ GET /github/search/issues?q={query}&per_page=30
588
+ ```
589
+
590
+ Example queries:
591
+ - `bug+is:open+is:issue` - Open issues containing "bug"
592
+ - `author:username+is:pr` - Pull requests by author
593
+
594
+ #### Search Code
595
+
596
+ ```bash
597
+ GET /github/search/code?q={query}&per_page=30
598
+ ```
599
+
600
+ Example queries:
601
+ - `addClass+repo:facebook/react` - Search for "addClass" in a specific repo
602
+ - `function+extension:js` - JavaScript functions
603
+
604
+ Note: Code search may timeout on broad queries.
605
+
606
+ #### Search Users
607
+
608
+ ```bash
609
+ GET /github/search/users?q={query}&per_page=30
610
+ ```
611
+
612
+ ### Organizations
613
+
614
+ #### List User Organizations
615
+
616
+ ```bash
617
+ GET /github/user/orgs?per_page=30
618
+ ```
619
+
620
+ Note: Requires `read:org` scope.
621
+
622
+ #### Get Organization
623
+
624
+ ```bash
625
+ GET /github/orgs/{org}
626
+ ```
627
+
628
+ #### List Organization Members
629
+
630
+ ```bash
631
+ GET /github/orgs/{org}/members?per_page=30
632
+ ```
633
+
634
+ ### Rate Limit
635
+
636
+ #### Get Rate Limit
637
+
638
+ ```bash
639
+ GET /github/rate_limit
640
+ ```
641
+
642
+ Response:
643
+ ```json
644
+ {
645
+ "rate": {
646
+ "limit": 5000,
647
+ "remaining": 4979,
648
+ "reset": 1707200000
649
+ },
650
+ "resources": {
651
+ "core": { "limit": 5000, "remaining": 4979 },
652
+ "search": { "limit": 30, "remaining": 28 }
653
+ }
654
+ }
655
+ ```
656
+
657
+ ## Pagination
658
+
659
+ GitHub uses page-based and link-based pagination:
660
+
661
+ ```bash
662
+ GET /github/repos/{owner}/{repo}/issues?per_page=30&page=2
663
+ ```
664
+
665
+ Response headers include pagination links:
666
+ - `Link: <url>; rel="next", <url>; rel="last"`
667
+
668
+ Common pagination parameters:
669
+ - `per_page`: Results per page (max 100, default 30)
670
+ - `page`: Page number (default 1)
671
+
672
+ Some endpoints use cursor-based pagination with `since` parameter (e.g., listing users).
673
+
674
+ ## Code Examples
675
+
676
+ ### JavaScript
677
+
678
+ ```javascript
679
+ const response = await fetch(
680
+ 'https://gateway.maton.ai/github/repos/owner/repo/issues?state=open&per_page=10',
681
+ {
682
+ headers: {
683
+ 'Authorization': `Bearer ${process.env.MATON_API_KEY}`
684
+ }
685
+ }
686
+ );
687
+ const issues = await response.json();
688
+ ```
689
+
690
+ ### Python
691
+
692
+ ```python
693
+ import os
694
+ import requests
695
+
696
+ response = requests.get(
697
+ 'https://gateway.maton.ai/github/repos/owner/repo/issues',
698
+ headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
699
+ params={'state': 'open', 'per_page': 10}
700
+ )
701
+ issues = response.json()
702
+ ```
703
+
704
+ ## Notes
705
+
706
+ - Repository names are case-insensitive but the API preserves case
707
+ - Issue numbers and PR numbers share the same sequence per repository
708
+ - Content must be Base64 encoded when creating/updating files
709
+ - Rate limits: 5000 requests/hour for authenticated users, 30 searches/minute
710
+ - Search queries may timeout on very broad patterns
711
+ - Some endpoints require specific OAuth scopes (e.g., `read:org` for organization operations). If you receive a scope error, contact Maton support at support@maton.ai with the specific operations/APIs you need and your use-case
712
+ - IMPORTANT: When using curl commands, use `curl -g` when URLs contain brackets to disable glob parsing
713
+ - IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments
714
+
715
+ ## Error Handling
716
+
717
+ | Status | Meaning |
718
+ |--------|---------|
719
+ | 400 | Missing GitHub connection |
720
+ | 401 | Invalid or missing Maton API key |
721
+ | 403 | Forbidden - insufficient permissions or scope |
722
+ | 404 | Resource not found |
723
+ | 408 | Request timeout (common for complex searches) |
724
+ | 422 | Validation failed |
725
+ | 429 | Rate limited |
726
+ | 4xx/5xx | Passthrough error from GitHub API |
727
+
728
+ ### Troubleshooting: API Key Issues
729
+
730
+ 1. Check that the `MATON_API_KEY` environment variable is set:
731
+
732
+ ```bash
733
+ echo $MATON_API_KEY
734
+ ```
735
+
736
+ 2. Verify the API key is valid by listing connections:
737
+
738
+ ```bash
739
+ python <<'EOF'
740
+ import urllib.request, os, json
741
+ req = urllib.request.Request('https://ctrl.maton.ai/connections')
742
+ req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
743
+ print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
744
+ EOF
745
+ ```
746
+
747
+ ### Troubleshooting: Invalid App Name
748
+
749
+ 1. Ensure your URL path starts with `github`. For example:
750
+
751
+ - Correct: `https://gateway.maton.ai/github/user`
752
+ - Incorrect: `https://gateway.maton.ai/api.github.com/user`
753
+
754
+ ## Resources
755
+
756
+ - [GitHub REST API Documentation](https://docs.github.com/en/rest)
757
+ - [Repositories API](https://docs.github.com/en/rest/repos/repos)
758
+ - [Issues API](https://docs.github.com/en/rest/issues/issues)
759
+ - [Pull Requests API](https://docs.github.com/en/rest/pulls/pulls)
760
+ - [Search API](https://docs.github.com/en/rest/search/search)
761
+ - [Rate Limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting)
762
+ - [Maton Community](https://discord.com/invite/dBfFAcefs2)
763
+ - [Maton Support](mailto:support@maton.ai)