cai-miner 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.
- cai_miner-0.1.0/CHANGELOG.md +32 -0
- cai_miner-0.1.0/CITATION.cff +40 -0
- cai_miner-0.1.0/LICENSE +21 -0
- cai_miner-0.1.0/PKG-INFO +210 -0
- cai_miner-0.1.0/README.md +179 -0
- cai_miner-0.1.0/docs/catalogue.md +109 -0
- cai_miner-0.1.0/docs/cloning.md +60 -0
- cai_miner-0.1.0/docs/ghaw.md +31 -0
- cai_miner-0.1.0/docs/output.md +107 -0
- cai_miner-0.1.0/pyproject.toml +169 -0
- cai_miner-0.1.0/pyproject.toml.orig +141 -0
- cai_miner-0.1.0/src/cai_miner/__init__.py +19 -0
- cai_miner-0.1.0/src/cai_miner/__main__.py +5 -0
- cai_miner-0.1.0/src/cai_miner/catalogues/catalogue.toml +38 -0
- cai_miner-0.1.0/src/cai_miner/catalogues/default.toml +169 -0
- cai_miner-0.1.0/src/cai_miner/catalogues/marketplace.toml +1180 -0
- cai_miner-0.1.0/src/cai_miner/cli.py +319 -0
- cai_miner-0.1.0/src/cai_miner/config.py +278 -0
- cai_miner-0.1.0/src/cai_miner/detect.py +385 -0
- cai_miner-0.1.0/src/cai_miner/extract.py +339 -0
- cai_miner-0.1.0/src/cai_miner/ghaw.py +272 -0
- cai_miner-0.1.0/src/cai_miner/gitlog.py +421 -0
- cai_miner-0.1.0/src/cai_miner/py.typed +0 -0
- cai_miner-0.1.0/tests/test_cai_miner.py +927 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to cai-miner are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-11-10
|
|
10
|
+
|
|
11
|
+
First public release. This is the version GHAgentCI was mined with; until then
|
|
12
|
+
the tool was developed under the working name `awe`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `cai-miner` command (also `python -m cai_miner`) that walks the first-parent
|
|
17
|
+
history of each workflow file in local git clones and detects coding-agent
|
|
18
|
+
invocations in every revision.
|
|
19
|
+
- Tiered evidence: `uses`, `run`, `path` and `ghaw` are strong; `job`, `url`
|
|
20
|
+
and `env` are weak and only count with `--include-weak`.
|
|
21
|
+
- Exact detection of GitHub Agentic Workflows from the compiler header, and
|
|
22
|
+
full parsing of their manifests into `ghaw_manifests.csv`.
|
|
23
|
+
- Outputs `repositories.csv`, `revisions.csv`, `steps.csv` and
|
|
24
|
+
`ghaw_manifests.csv`, plus an optional content-addressed store of every
|
|
25
|
+
distinct workflow revision.
|
|
26
|
+
- Bundled, frozen detector catalogues (`catalogue.toml`, `default.toml`,
|
|
27
|
+
`marketplace.toml`); `catalogue.toml` is the default.
|
|
28
|
+
- Blob accounting and bulk backfill for partial clones, so incomplete
|
|
29
|
+
repositories are reported rather than silently under-counted.
|
|
30
|
+
|
|
31
|
+
[Unreleased]: https://github.com/unlv-evol/cai-miner/compare/v0.1.0...HEAD
|
|
32
|
+
[0.1.0]: https://github.com/unlv-evol/cai-miner/releases/tag/v0.1.0
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this tool, please cite it as below."
|
|
3
|
+
title: "cai-miner: Coding-Agent Invocations Miner"
|
|
4
|
+
abstract: >-
|
|
5
|
+
A command line tool that mines the git history of CI workflow files and
|
|
6
|
+
detects coding-agent invocations inside them, including GitHub Agentic
|
|
7
|
+
Workflows, for large-scale studies of agentic continuous integration on
|
|
8
|
+
GitHub.
|
|
9
|
+
version: 0.1.0
|
|
10
|
+
license: MIT
|
|
11
|
+
repository-code: "https://github.com/unlv-evol/cai-miner"
|
|
12
|
+
url: "https://pypi.org/project/cai-miner/"
|
|
13
|
+
type: software
|
|
14
|
+
keywords:
|
|
15
|
+
- mining software repositories
|
|
16
|
+
- continuous integration
|
|
17
|
+
- GitHub Actions
|
|
18
|
+
- coding agents
|
|
19
|
+
- dataset
|
|
20
|
+
authors:
|
|
21
|
+
- family-names: "Ogenrwot"
|
|
22
|
+
given-names: "Daniel"
|
|
23
|
+
email: "ogenrwot@unlv.nevada.edu"
|
|
24
|
+
affiliation: "University of Nevada, Las Vegas"
|
|
25
|
+
orcid: "https://orcid.org/0000-0002-0133-8164"
|
|
26
|
+
- family-names: "Delgado Cervantes"
|
|
27
|
+
given-names: "Jorge Gonzalo"
|
|
28
|
+
email: "delgaj10@unlv.nevada.edu"
|
|
29
|
+
affiliation: "University of Nevada, Las Vegas"
|
|
30
|
+
orcid: "https://orcid.org/0009-0005-5155-8914"
|
|
31
|
+
- family-names: "Kim"
|
|
32
|
+
given-names: "Woojoong"
|
|
33
|
+
email: "kimw19@unlv.nevada.edu"
|
|
34
|
+
affiliation: "University of Nevada, Las Vegas"
|
|
35
|
+
orcid: "https://orcid.org/0009-0007-8068-1035"
|
|
36
|
+
- family-names: "Businge"
|
|
37
|
+
given-names: "John"
|
|
38
|
+
email: "john.businge@unlv.edu"
|
|
39
|
+
affiliation: "University of Nevada, Las Vegas"
|
|
40
|
+
orcid: "https://orcid.org/0000-0003-3206-7085"
|
cai_miner-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The cai-miner authors
|
|
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.
|
cai_miner-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cai-miner
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Mine coding-agent invocations from the git history of GitHub Actions workflows
|
|
5
|
+
Keywords: mining software repositories,github actions,continuous integration,coding agents,llm,dataset
|
|
6
|
+
Author: Daniel Ogenrwot, Jorge Gonzalo Delgado Cervantes, Woojoong Kim, John Businge
|
|
7
|
+
Author-email: Daniel Ogenrwot <ogenrwot@unlv.nevada.edu>, Jorge Gonzalo Delgado Cervantes <delgaj10@unlv.nevada.edu>, Woojoong Kim <kimw19@unlv.nevada.edu>, John Businge <john.businge@unlv.edu>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: POSIX
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Project-URL: Homepage, https://github.com/unlv-evol/cai-miner
|
|
27
|
+
Project-URL: Repository, https://github.com/unlv-evol/cai-miner
|
|
28
|
+
Project-URL: Issues, https://github.com/unlv-evol/cai-miner/issues
|
|
29
|
+
Project-URL: Changelog, https://github.com/unlv-evol/cai-miner/blob/main/CHANGELOG.md
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# cai-miner
|
|
33
|
+
|
|
34
|
+
[](https://github.com/unlv-evol/cai-miner/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/cai-miner/)
|
|
36
|
+
[](https://pypi.org/project/cai-miner/)
|
|
37
|
+
[](https://github.com/unlv-evol/cai-miner/blob/main/LICENSE)
|
|
38
|
+
|
|
39
|
+
**cai-miner** (Coding-Agent Invocations miner) mines the git history of GitHub
|
|
40
|
+
Actions workflow files and finds the **coding-agent invocations** inside them:
|
|
41
|
+
the steps that run Claude Code, Codex, Copilot, Gemini, Cursor, Aider and
|
|
42
|
+
similar agents as part of a repository's continuous integration.
|
|
43
|
+
|
|
44
|
+
For every workflow file that invokes an agent at some point, it emits the
|
|
45
|
+
file's whole history (before the agent arrived, while it was there, and after
|
|
46
|
+
it was removed), one row per agent invocation, and repository-level
|
|
47
|
+
denominators. It is the tool behind the **GHAgentCI** dataset.
|
|
48
|
+
|
|
49
|
+
## Why content-based detection
|
|
50
|
+
|
|
51
|
+
Agent context files such as `CLAUDE.md` or `AGENTS.md` can be classified by
|
|
52
|
+
path, since the filename names the agent. An agentic CI workflow cannot: it is
|
|
53
|
+
an ordinary `.github/workflows/whatever.yml`, indistinguishable by name from a
|
|
54
|
+
build or lint workflow. cai-miner therefore parses every revision of every
|
|
55
|
+
workflow file, walks its jobs and steps, and matches each step against a
|
|
56
|
+
catalogue of agents.
|
|
57
|
+
|
|
58
|
+
Not every mention of an agent is an invocation; a workflow that sets
|
|
59
|
+
`ANTHROPIC_API_KEY` may just be feeding a test suite. Evidence is therefore
|
|
60
|
+
tiered:
|
|
61
|
+
|
|
62
|
+
| evidence | meaning | strength |
|
|
63
|
+
| -------- | ------- | -------- |
|
|
64
|
+
| `uses` | a step invokes a dedicated agent GitHub Action | strong |
|
|
65
|
+
| `run` | a step shell-invokes an agent CLI | strong |
|
|
66
|
+
| `path` | the workflow file has a reserved, agent-specific name | strong |
|
|
67
|
+
| `ghaw` | the file was compiled by GitHub Agentic Workflows | strong |
|
|
68
|
+
| `job` | a job carries a reserved, agent-specific id | weak |
|
|
69
|
+
| `url` | a step talks to an LLM inference endpoint | weak |
|
|
70
|
+
| `env` | an agent or LLM credential is bound at that scope | weak |
|
|
71
|
+
|
|
72
|
+
A revision counts as agentic only with strong evidence, unless you pass
|
|
73
|
+
`--include-weak`.
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
cai-miner needs Python 3.11 or newer and `git` 2.30 or newer on the `PATH`. Its
|
|
78
|
+
only Python dependency is PyYAML.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uv tool install cai-miner # recommended: an isolated, global command
|
|
82
|
+
pipx install cai-miner # equivalent with pipx
|
|
83
|
+
pip install cai-miner # into the current environment
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Or run it once without installing: `uvx cai-miner --help`.
|
|
87
|
+
|
|
88
|
+
## Quickstart
|
|
89
|
+
|
|
90
|
+
cai-miner works on local clones. A size-capped partial clone without a working
|
|
91
|
+
tree is the fastest way to get one (see [cloning](https://github.com/unlv-evol/cai-miner/blob/main/docs/cloning.md)):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone --filter=blob:limit=64k --no-checkout --single-branch \
|
|
95
|
+
https://github.com/vitejs/vite.git clones/vite
|
|
96
|
+
|
|
97
|
+
# Agent invocations across the whole history, as CSV on stdout
|
|
98
|
+
cai-miner clones/vite
|
|
99
|
+
|
|
100
|
+
# Full outputs for many clones, plus every distinct workflow revision
|
|
101
|
+
cai-miner --from-file clones.txt -o out/ --content-dir out/content
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
With `-o out/` you get:
|
|
105
|
+
|
|
106
|
+
| file | one row per |
|
|
107
|
+
| ---- | ----------- |
|
|
108
|
+
| `repositories.csv` | repository, agentic or not, including failures |
|
|
109
|
+
| `revisions.csv` | change to a workflow file whose history is agentic at some point |
|
|
110
|
+
| `steps.csv` | agent invocation |
|
|
111
|
+
| `ghaw_manifests.csv` | revision of a GitHub Agentic Workflows source or compiled file |
|
|
112
|
+
|
|
113
|
+
Every column is documented in the
|
|
114
|
+
[output reference](https://github.com/unlv-evol/cai-miner/blob/main/docs/output.md).
|
|
115
|
+
|
|
116
|
+
## Command-line reference
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
cai-miner [options] [REPOSITORY ...]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| option | effect |
|
|
123
|
+
| ------ | ------ |
|
|
124
|
+
| `-c`, `--config FILE` | detector catalogue (TOML); defaults to the bundled frozen catalogue |
|
|
125
|
+
| `--from-file FILE` | read clone paths from a file, one per line |
|
|
126
|
+
| `-o`, `--out-dir DIR` | write the four CSV files to `DIR` |
|
|
127
|
+
| `--content-dir DIR` | store each distinct workflow revision as `DIR/<sha256>.yml` |
|
|
128
|
+
| `--rev REV` | commit to start the history walk from (default `HEAD`) |
|
|
129
|
+
| `--since DATE` | ignore commits older than `DATE`, e.g. `2024-01-01` |
|
|
130
|
+
| `--include-weak` | let `job`, `url` and `env` evidence make a revision agentic |
|
|
131
|
+
| `--keep-all` | emit every workflow revision, not only agentic histories |
|
|
132
|
+
| `--no-prefetch` | disable the bulk blob prefetch on partial clones |
|
|
133
|
+
| `--repository OWNER/NAME` | name of the single repository given, instead of reading it from the clone's remote |
|
|
134
|
+
| `--fail-fast` | stop at the first repository that fails |
|
|
135
|
+
| `-q`, `--quiet` | suppress progress output |
|
|
136
|
+
| `--version` | print the version and exit |
|
|
137
|
+
|
|
138
|
+
`python -m cai_miner` is equivalent to `cai-miner`.
|
|
139
|
+
|
|
140
|
+
## Detector catalogue
|
|
141
|
+
|
|
142
|
+
Agents and their patterns live in a TOML catalogue; adding an agent needs no
|
|
143
|
+
code changes:
|
|
144
|
+
|
|
145
|
+
```toml
|
|
146
|
+
[agents.myagent]
|
|
147
|
+
display_name = "My Agent"
|
|
148
|
+
uses = ["myorg/my-agent-action"]
|
|
149
|
+
run = ["myagent --run"]
|
|
150
|
+
env = ["MYAGENT_API_KEY"]
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The bundled default is the catalogue GHAgentCI was mined with: a hand-written
|
|
154
|
+
catalogue drawn from vendor documentation, merged with one generated from the
|
|
155
|
+
GitHub Marketplace `ai-assisted` category. See the
|
|
156
|
+
[catalogue reference](https://github.com/unlv-evol/cai-miner/blob/main/docs/catalogue.md)
|
|
157
|
+
for the format, includes, aliases and overrides.
|
|
158
|
+
|
|
159
|
+
Files generated by [GitHub Agentic Workflows](https://github.com/github/gh-aw)
|
|
160
|
+
are detected from the compiler's own header, with no catalogue involved, and
|
|
161
|
+
their manifests are parsed in full; see
|
|
162
|
+
[gh-aw](https://github.com/unlv-evol/cai-miner/blob/main/docs/ghaw.md).
|
|
163
|
+
|
|
164
|
+
## Using it from Python
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from cai_miner.config import load_config
|
|
168
|
+
from cai_miner.detect import analyse
|
|
169
|
+
from cai_miner.extract import extract_repository
|
|
170
|
+
|
|
171
|
+
catalogue = load_config() # the bundled catalogue; or load_config("my.toml")
|
|
172
|
+
|
|
173
|
+
# Classify one workflow revision
|
|
174
|
+
facts = analyse(catalogue, open("ci.yml").read(), ".github/workflows/ci.yml")
|
|
175
|
+
print(facts.strong_agents)
|
|
176
|
+
|
|
177
|
+
# Mine one local clone
|
|
178
|
+
result = extract_repository("clones/vite", catalogue)
|
|
179
|
+
print(result.summary.n_agentic_files, len(result.steps))
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The command line is the stable interface; the Python modules may change
|
|
183
|
+
between minor versions before 1.0.
|
|
184
|
+
|
|
185
|
+
## Reproducing GHAgentCI
|
|
186
|
+
|
|
187
|
+
The GHAgentCI dataset and its replication package are archived on Zenodo at
|
|
188
|
+
[doi:10.5281/zenodo.24088832](https://doi.org/10.5281/zenodo.24088832). This
|
|
189
|
+
repository also holds the scripts and validation material behind it; they are
|
|
190
|
+
not part of the installed package:
|
|
191
|
+
|
|
192
|
+
- [`docs/FULL_RUN.md`](https://github.com/unlv-evol/cai-miner/blob/main/docs/FULL_RUN.md): how the full mining run was set up, monitored and resumed;
|
|
193
|
+
- [`docs/DATASET.md`](https://github.com/unlv-evol/cai-miner/blob/main/docs/DATASET.md): the released tables, field by field;
|
|
194
|
+
- [`BENCHMARKS.md`](https://github.com/unlv-evol/cai-miner/blob/main/BENCHMARKS.md): throughput and clone-strategy measurements.
|
|
195
|
+
|
|
196
|
+
## Citing
|
|
197
|
+
|
|
198
|
+
If you use cai-miner or GHAgentCI in research, please cite it; GitHub's
|
|
199
|
+
"Cite this repository" button reads
|
|
200
|
+
[`CITATION.cff`](https://github.com/unlv-evol/cai-miner/blob/main/CITATION.cff).
|
|
201
|
+
|
|
202
|
+
## Contributing
|
|
203
|
+
|
|
204
|
+
Bug reports and pull requests are welcome. See
|
|
205
|
+
[CONTRIBUTING.md](https://github.com/unlv-evol/cai-miner/blob/main/CONTRIBUTING.md)
|
|
206
|
+
for the development setup.
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
[MIT](https://github.com/unlv-evol/cai-miner/blob/main/LICENSE)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# cai-miner
|
|
2
|
+
|
|
3
|
+
[](https://github.com/unlv-evol/cai-miner/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/cai-miner/)
|
|
5
|
+
[](https://pypi.org/project/cai-miner/)
|
|
6
|
+
[](https://github.com/unlv-evol/cai-miner/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
**cai-miner** (Coding-Agent Invocations miner) mines the git history of GitHub
|
|
9
|
+
Actions workflow files and finds the **coding-agent invocations** inside them:
|
|
10
|
+
the steps that run Claude Code, Codex, Copilot, Gemini, Cursor, Aider and
|
|
11
|
+
similar agents as part of a repository's continuous integration.
|
|
12
|
+
|
|
13
|
+
For every workflow file that invokes an agent at some point, it emits the
|
|
14
|
+
file's whole history (before the agent arrived, while it was there, and after
|
|
15
|
+
it was removed), one row per agent invocation, and repository-level
|
|
16
|
+
denominators. It is the tool behind the **GHAgentCI** dataset.
|
|
17
|
+
|
|
18
|
+
## Why content-based detection
|
|
19
|
+
|
|
20
|
+
Agent context files such as `CLAUDE.md` or `AGENTS.md` can be classified by
|
|
21
|
+
path, since the filename names the agent. An agentic CI workflow cannot: it is
|
|
22
|
+
an ordinary `.github/workflows/whatever.yml`, indistinguishable by name from a
|
|
23
|
+
build or lint workflow. cai-miner therefore parses every revision of every
|
|
24
|
+
workflow file, walks its jobs and steps, and matches each step against a
|
|
25
|
+
catalogue of agents.
|
|
26
|
+
|
|
27
|
+
Not every mention of an agent is an invocation; a workflow that sets
|
|
28
|
+
`ANTHROPIC_API_KEY` may just be feeding a test suite. Evidence is therefore
|
|
29
|
+
tiered:
|
|
30
|
+
|
|
31
|
+
| evidence | meaning | strength |
|
|
32
|
+
| -------- | ------- | -------- |
|
|
33
|
+
| `uses` | a step invokes a dedicated agent GitHub Action | strong |
|
|
34
|
+
| `run` | a step shell-invokes an agent CLI | strong |
|
|
35
|
+
| `path` | the workflow file has a reserved, agent-specific name | strong |
|
|
36
|
+
| `ghaw` | the file was compiled by GitHub Agentic Workflows | strong |
|
|
37
|
+
| `job` | a job carries a reserved, agent-specific id | weak |
|
|
38
|
+
| `url` | a step talks to an LLM inference endpoint | weak |
|
|
39
|
+
| `env` | an agent or LLM credential is bound at that scope | weak |
|
|
40
|
+
|
|
41
|
+
A revision counts as agentic only with strong evidence, unless you pass
|
|
42
|
+
`--include-weak`.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
cai-miner needs Python 3.11 or newer and `git` 2.30 or newer on the `PATH`. Its
|
|
47
|
+
only Python dependency is PyYAML.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv tool install cai-miner # recommended: an isolated, global command
|
|
51
|
+
pipx install cai-miner # equivalent with pipx
|
|
52
|
+
pip install cai-miner # into the current environment
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or run it once without installing: `uvx cai-miner --help`.
|
|
56
|
+
|
|
57
|
+
## Quickstart
|
|
58
|
+
|
|
59
|
+
cai-miner works on local clones. A size-capped partial clone without a working
|
|
60
|
+
tree is the fastest way to get one (see [cloning](https://github.com/unlv-evol/cai-miner/blob/main/docs/cloning.md)):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone --filter=blob:limit=64k --no-checkout --single-branch \
|
|
64
|
+
https://github.com/vitejs/vite.git clones/vite
|
|
65
|
+
|
|
66
|
+
# Agent invocations across the whole history, as CSV on stdout
|
|
67
|
+
cai-miner clones/vite
|
|
68
|
+
|
|
69
|
+
# Full outputs for many clones, plus every distinct workflow revision
|
|
70
|
+
cai-miner --from-file clones.txt -o out/ --content-dir out/content
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
With `-o out/` you get:
|
|
74
|
+
|
|
75
|
+
| file | one row per |
|
|
76
|
+
| ---- | ----------- |
|
|
77
|
+
| `repositories.csv` | repository, agentic or not, including failures |
|
|
78
|
+
| `revisions.csv` | change to a workflow file whose history is agentic at some point |
|
|
79
|
+
| `steps.csv` | agent invocation |
|
|
80
|
+
| `ghaw_manifests.csv` | revision of a GitHub Agentic Workflows source or compiled file |
|
|
81
|
+
|
|
82
|
+
Every column is documented in the
|
|
83
|
+
[output reference](https://github.com/unlv-evol/cai-miner/blob/main/docs/output.md).
|
|
84
|
+
|
|
85
|
+
## Command-line reference
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
cai-miner [options] [REPOSITORY ...]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| option | effect |
|
|
92
|
+
| ------ | ------ |
|
|
93
|
+
| `-c`, `--config FILE` | detector catalogue (TOML); defaults to the bundled frozen catalogue |
|
|
94
|
+
| `--from-file FILE` | read clone paths from a file, one per line |
|
|
95
|
+
| `-o`, `--out-dir DIR` | write the four CSV files to `DIR` |
|
|
96
|
+
| `--content-dir DIR` | store each distinct workflow revision as `DIR/<sha256>.yml` |
|
|
97
|
+
| `--rev REV` | commit to start the history walk from (default `HEAD`) |
|
|
98
|
+
| `--since DATE` | ignore commits older than `DATE`, e.g. `2024-01-01` |
|
|
99
|
+
| `--include-weak` | let `job`, `url` and `env` evidence make a revision agentic |
|
|
100
|
+
| `--keep-all` | emit every workflow revision, not only agentic histories |
|
|
101
|
+
| `--no-prefetch` | disable the bulk blob prefetch on partial clones |
|
|
102
|
+
| `--repository OWNER/NAME` | name of the single repository given, instead of reading it from the clone's remote |
|
|
103
|
+
| `--fail-fast` | stop at the first repository that fails |
|
|
104
|
+
| `-q`, `--quiet` | suppress progress output |
|
|
105
|
+
| `--version` | print the version and exit |
|
|
106
|
+
|
|
107
|
+
`python -m cai_miner` is equivalent to `cai-miner`.
|
|
108
|
+
|
|
109
|
+
## Detector catalogue
|
|
110
|
+
|
|
111
|
+
Agents and their patterns live in a TOML catalogue; adding an agent needs no
|
|
112
|
+
code changes:
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[agents.myagent]
|
|
116
|
+
display_name = "My Agent"
|
|
117
|
+
uses = ["myorg/my-agent-action"]
|
|
118
|
+
run = ["myagent --run"]
|
|
119
|
+
env = ["MYAGENT_API_KEY"]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The bundled default is the catalogue GHAgentCI was mined with: a hand-written
|
|
123
|
+
catalogue drawn from vendor documentation, merged with one generated from the
|
|
124
|
+
GitHub Marketplace `ai-assisted` category. See the
|
|
125
|
+
[catalogue reference](https://github.com/unlv-evol/cai-miner/blob/main/docs/catalogue.md)
|
|
126
|
+
for the format, includes, aliases and overrides.
|
|
127
|
+
|
|
128
|
+
Files generated by [GitHub Agentic Workflows](https://github.com/github/gh-aw)
|
|
129
|
+
are detected from the compiler's own header, with no catalogue involved, and
|
|
130
|
+
their manifests are parsed in full; see
|
|
131
|
+
[gh-aw](https://github.com/unlv-evol/cai-miner/blob/main/docs/ghaw.md).
|
|
132
|
+
|
|
133
|
+
## Using it from Python
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from cai_miner.config import load_config
|
|
137
|
+
from cai_miner.detect import analyse
|
|
138
|
+
from cai_miner.extract import extract_repository
|
|
139
|
+
|
|
140
|
+
catalogue = load_config() # the bundled catalogue; or load_config("my.toml")
|
|
141
|
+
|
|
142
|
+
# Classify one workflow revision
|
|
143
|
+
facts = analyse(catalogue, open("ci.yml").read(), ".github/workflows/ci.yml")
|
|
144
|
+
print(facts.strong_agents)
|
|
145
|
+
|
|
146
|
+
# Mine one local clone
|
|
147
|
+
result = extract_repository("clones/vite", catalogue)
|
|
148
|
+
print(result.summary.n_agentic_files, len(result.steps))
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The command line is the stable interface; the Python modules may change
|
|
152
|
+
between minor versions before 1.0.
|
|
153
|
+
|
|
154
|
+
## Reproducing GHAgentCI
|
|
155
|
+
|
|
156
|
+
The GHAgentCI dataset and its replication package are archived on Zenodo at
|
|
157
|
+
[doi:10.5281/zenodo.24088832](https://doi.org/10.5281/zenodo.24088832). This
|
|
158
|
+
repository also holds the scripts and validation material behind it; they are
|
|
159
|
+
not part of the installed package:
|
|
160
|
+
|
|
161
|
+
- [`docs/FULL_RUN.md`](https://github.com/unlv-evol/cai-miner/blob/main/docs/FULL_RUN.md): how the full mining run was set up, monitored and resumed;
|
|
162
|
+
- [`docs/DATASET.md`](https://github.com/unlv-evol/cai-miner/blob/main/docs/DATASET.md): the released tables, field by field;
|
|
163
|
+
- [`BENCHMARKS.md`](https://github.com/unlv-evol/cai-miner/blob/main/BENCHMARKS.md): throughput and clone-strategy measurements.
|
|
164
|
+
|
|
165
|
+
## Citing
|
|
166
|
+
|
|
167
|
+
If you use cai-miner or GHAgentCI in research, please cite it; GitHub's
|
|
168
|
+
"Cite this repository" button reads
|
|
169
|
+
[`CITATION.cff`](https://github.com/unlv-evol/cai-miner/blob/main/CITATION.cff).
|
|
170
|
+
|
|
171
|
+
## Contributing
|
|
172
|
+
|
|
173
|
+
Bug reports and pull requests are welcome. See
|
|
174
|
+
[CONTRIBUTING.md](https://github.com/unlv-evol/cai-miner/blob/main/CONTRIBUTING.md)
|
|
175
|
+
for the development setup.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
[MIT](https://github.com/unlv-evol/cai-miner/blob/main/LICENSE)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Detector catalogue
|
|
2
|
+
|
|
3
|
+
Detection is driven by a TOML catalogue of agents and the patterns that
|
|
4
|
+
identify them. Three catalogues ship inside the package, in
|
|
5
|
+
`src/cai_miner/catalogues/`:
|
|
6
|
+
|
|
7
|
+
| file | what it is |
|
|
8
|
+
| ---- | ---------- |
|
|
9
|
+
| `catalogue.toml` | **the default.** The frozen catalogue GHAgentCI was mined with: `default.toml` and `marketplace.toml` merged. |
|
|
10
|
+
| `default.toml` | hand-written from vendor documentation: `run`, `url`, `env`, `path` and `job` patterns, plus the `[paths]`, `[tasks]` and `[exclude]` sections |
|
|
11
|
+
| `marketplace.toml` | generated from the GitHub Marketplace `ai-assisted` category: the long tail of `uses` patterns |
|
|
12
|
+
|
|
13
|
+
Pass `-c my.toml` to use your own. From Python, the bundled files are under
|
|
14
|
+
`cai_miner.config.CATALOGUES`.
|
|
15
|
+
|
|
16
|
+
## Evidence kinds
|
|
17
|
+
|
|
18
|
+
| kind | matches | strength |
|
|
19
|
+
| ------ | ------------------------------------------------------- | -------- |
|
|
20
|
+
| `uses` | a step's `uses:` names a dedicated agent action | strong |
|
|
21
|
+
| `run` | a step's `run:` shell-invokes an agent CLI | strong |
|
|
22
|
+
| `path` | the workflow file has a reserved, agent-specific name | strong |
|
|
23
|
+
| `ghaw` | the file was generated by GitHub Agentic Workflows | strong |
|
|
24
|
+
| `job` | a job carries a reserved, agent-specific id | weak |
|
|
25
|
+
| `url` | a step talks to an LLM inference endpoint | weak |
|
|
26
|
+
| `env` | an agent or LLM credential is bound at that scope | weak |
|
|
27
|
+
|
|
28
|
+
A revision is agentic only if it carries strong evidence, unless
|
|
29
|
+
`--include-weak` is given. `ghaw` needs no pattern: the gh-aw compiler
|
|
30
|
+
identifies its own output (see [GitHub Agentic Workflows](ghaw.md)).
|
|
31
|
+
|
|
32
|
+
Why a filename can be strong evidence: GitHub's Copilot coding agent is wired
|
|
33
|
+
in by reserved filename. GitHub reads `.github/workflows/copilot-setup-steps.yml`
|
|
34
|
+
and runs the job of the same name, and neither carries a `uses:` or `run:` that
|
|
35
|
+
names Copilot. The reserved *file* is the contract GitHub honours, whereas the
|
|
36
|
+
reserved *job id* in some other file is a copied template GitHub never reads,
|
|
37
|
+
so only the former is strong.
|
|
38
|
+
|
|
39
|
+
`env` evidence is attributed **once, at the scope that declares it**: a step's
|
|
40
|
+
own `env:` to that step, a job's to the job, the workflow's to the workflow.
|
|
41
|
+
Folding outer scopes into each step would claim `actions/checkout` is an agent
|
|
42
|
+
invocation because the workflow exports `ANTHROPIC_API_KEY` at the top.
|
|
43
|
+
|
|
44
|
+
## Matching
|
|
45
|
+
|
|
46
|
+
`uses` patterns match an action exactly: `owner/repo` matches `owner/repo@v1`
|
|
47
|
+
and `owner/repo/sub@v1`, but not `owner/repo-other` or `xowner/repo`. The other
|
|
48
|
+
kinds match as case-insensitive substrings.
|
|
49
|
+
|
|
50
|
+
## Format
|
|
51
|
+
|
|
52
|
+
```toml
|
|
53
|
+
# Which files are CI workflows at all.
|
|
54
|
+
[paths]
|
|
55
|
+
github_actions = [".github/workflows/*.yml", ".github/workflows/*.yaml"]
|
|
56
|
+
|
|
57
|
+
[agents.myagent]
|
|
58
|
+
display_name = "My Agent"
|
|
59
|
+
uses = ["myorg/my-agent-action"]
|
|
60
|
+
run = ["myagent --run"]
|
|
61
|
+
env = ["MYAGENT_API_KEY"]
|
|
62
|
+
url = ["api.myagent.example"]
|
|
63
|
+
path = [".github/workflows/myagent-setup.yml"]
|
|
64
|
+
job = ["myagent-setup"]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Extending detection needs no code changes. Copy `default.toml` as a starting
|
|
68
|
+
point; it also shows the `[tasks]` and `[exclude]` sections.
|
|
69
|
+
|
|
70
|
+
### Composing catalogues
|
|
71
|
+
|
|
72
|
+
A catalogue may `include` others, resolved relative to its own location:
|
|
73
|
+
|
|
74
|
+
```toml
|
|
75
|
+
include = ["default.toml", "marketplace.toml"]
|
|
76
|
+
|
|
77
|
+
# Rename an agent group from an included file.
|
|
78
|
+
[aliases]
|
|
79
|
+
qodo = "pr_agent"
|
|
80
|
+
|
|
81
|
+
# Move one `uses` pattern to a different group.
|
|
82
|
+
[overrides]
|
|
83
|
+
"codota/tabnine-pr-agent" = "generic_ai"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Patterns are unioned per agent group, and `[aliases]` and `[overrides]` apply
|
|
87
|
+
after merging. This is how `catalogue.toml` is built without editing either
|
|
88
|
+
source file, so the generated one can still be regenerated and diffed.
|
|
89
|
+
|
|
90
|
+
## The frozen dataset catalogue
|
|
91
|
+
|
|
92
|
+
`catalogue.toml`, `default.toml` and `marketplace.toml` are frozen at the
|
|
93
|
+
versions that produced GHAgentCI, and a test checks their SHA-256 sums. The
|
|
94
|
+
dataset's validation sample only holds for the patterns that produced the
|
|
95
|
+
data, so a change to detection belongs in a new catalogue file, not in these.
|
|
96
|
+
|
|
97
|
+
## Regenerating the Marketplace catalogue
|
|
98
|
+
|
|
99
|
+
`marketplace.toml` is produced by a script in the source repository (not part
|
|
100
|
+
of the installed package):
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv run python scripts/build_catalogue.py -o new-marketplace.toml
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
It enumerates the Marketplace `ai-assisted` category, resolves each listing to
|
|
107
|
+
its source repository, and groups repositories belonging to a known agent
|
|
108
|
+
vendor under that agent, with everything else under `generic_ai`. Vendor
|
|
109
|
+
grouping rules live in `_AGENT_RULES` in the script.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Cloning repositories for cai-miner
|
|
2
|
+
|
|
3
|
+
`cai-miner` reads local clones; it never talks to the GitHub API. How you clone
|
|
4
|
+
decides how long a run takes and how much disk it needs. Measured numbers are
|
|
5
|
+
in [BENCHMARKS.md](../BENCHMARKS.md).
|
|
6
|
+
|
|
7
|
+
## Recommended: a size-capped blob filter
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone --filter=blob:limit=64k --no-checkout --single-branch \
|
|
11
|
+
https://github.com/OWNER/NAME.git
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
A size cap fetches everything `cai-miner` reads in a single server-built
|
|
15
|
+
packfile while leaving large blobs behind. `--no-checkout` skips the working
|
|
16
|
+
tree, which the tool does not need. Both caps below produce byte-identical
|
|
17
|
+
output; the choice is a time and bandwidth trade:
|
|
18
|
+
|
|
19
|
+
| repository | class | cap | total | disk |
|
|
20
|
+
| ---------- | ----- | --- | ----- | ---- |
|
|
21
|
+
| vite | ordinary | **64k** | **5 s** | **31 MB** |
|
|
22
|
+
| vite | | 1m | 7 s | 66 MB |
|
|
23
|
+
| langchain | large | **64k** | **18 s** | **108 MB** |
|
|
24
|
+
| langchain | | 1m | 33 s | 300 MB |
|
|
25
|
+
| godot | large | **64k** | **42 s** | **454 MB** |
|
|
26
|
+
| godot | | 1m | 71 s | 1176 MB |
|
|
27
|
+
| amplihack | gh-aw adopter | 64k | 41 s | 48 MB |
|
|
28
|
+
| amplihack | | **1m** | **16 s** | 196 MB |
|
|
29
|
+
|
|
30
|
+
`64k` wins everywhere except on gh-aw adopters, whose compiled workflows reach
|
|
31
|
+
240 kB and so have to be backfilled, and a backfill costs a full fetch
|
|
32
|
+
negotiation per repository however few objects it needs. Since gh-aw adopters
|
|
33
|
+
are about 1% of repositories, prefer `1m` only for a gh-aw-heavy list.
|
|
34
|
+
|
|
35
|
+
A workflow file larger than the cap is not lost: `cai-miner` detects which
|
|
36
|
+
blobs are absent locally (without network access, by running `git cat-file`
|
|
37
|
+
under `GIT_NO_LAZY_FETCH`) and bulk-fetches exactly those. The blob-accounting
|
|
38
|
+
columns in `repositories.csv` make the outcome checkable.
|
|
39
|
+
|
|
40
|
+
## Strategies to avoid
|
|
41
|
+
|
|
42
|
+
| strategy | vite | uv |
|
|
43
|
+
| -------- | ---- | -- |
|
|
44
|
+
| blobless (`--filter=blob:none`) + prefetch | 210 s | >300 s (timeout) |
|
|
45
|
+
| full clone, no filter | 13 s | 72 s |
|
|
46
|
+
|
|
47
|
+
On a blobless clone, `git cat-file` backfills missing blobs one network round
|
|
48
|
+
trip at a time, and requesting the object ids up front does not fix it:
|
|
49
|
+
`git fetch <oids>` costs server-side resolution against the whole repository,
|
|
50
|
+
roughly independent of how many ids you ask for. `cai-miner` still detects a
|
|
51
|
+
partial clone and prefetches in bulk as a fallback (disable with
|
|
52
|
+
`--no-prefetch`), but a `blob:limit` clone is faster and simpler.
|
|
53
|
+
|
|
54
|
+
## Sizing a large run
|
|
55
|
+
|
|
56
|
+
With a capped clone, **extraction, not cloning, is the bottleneck** on large
|
|
57
|
+
repositories: most CPU time goes to YAML parsing. Extraction parallelises
|
|
58
|
+
across repositories (run several `cai-miner` processes on disjoint lists,
|
|
59
|
+
sharing one `--content-dir`), while clone bandwidth does not. Size a large run
|
|
60
|
+
on cores rather than network.
|