circuitcheck 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 (34) hide show
  1. circuitcheck-0.1.0/LICENSE +21 -0
  2. circuitcheck-0.1.0/PKG-INFO +171 -0
  3. circuitcheck-0.1.0/README.md +130 -0
  4. circuitcheck-0.1.0/pyproject.toml +134 -0
  5. circuitcheck-0.1.0/pyproject.toml.orig +95 -0
  6. circuitcheck-0.1.0/src/circuitcheck/__init__.py +16 -0
  7. circuitcheck-0.1.0/src/circuitcheck/cli.py +236 -0
  8. circuitcheck-0.1.0/src/circuitcheck/diff/__init__.py +27 -0
  9. circuitcheck-0.1.0/src/circuitcheck/diff/core.py +502 -0
  10. circuitcheck-0.1.0/src/circuitcheck/diff/graphs.py +213 -0
  11. circuitcheck-0.1.0/src/circuitcheck/labels/__init__.py +42 -0
  12. circuitcheck-0.1.0/src/circuitcheck/labels/autointerp.py +383 -0
  13. circuitcheck-0.1.0/src/circuitcheck/labels/neuronpedia.py +148 -0
  14. circuitcheck-0.1.0/src/circuitcheck/labels/providers.py +200 -0
  15. circuitcheck-0.1.0/src/circuitcheck/py.typed +0 -0
  16. circuitcheck-0.1.0/src/circuitcheck/report.py +290 -0
  17. circuitcheck-0.1.0/src/circuitcheck/tracer.py +165 -0
  18. circuitcheck-0.1.0/src/circuitcheck/validate/__init__.py +33 -0
  19. circuitcheck-0.1.0/src/circuitcheck/validate/backend.py +41 -0
  20. circuitcheck-0.1.0/src/circuitcheck/validate/controls.py +81 -0
  21. circuitcheck-0.1.0/src/circuitcheck/validate/core.py +330 -0
  22. circuitcheck-0.1.0/src/circuitcheck/validate/metrics.py +49 -0
  23. circuitcheck-0.1.0/src/circuitcheck/validate/sandbox.py +129 -0
  24. circuitcheck-0.1.0/src/circuitcheck/validate/toy.py +139 -0
  25. circuitcheck-0.1.0/src/circuitcheck/validate/types.py +142 -0
  26. circuitcheck-0.1.0/tests/__init__.py +0 -0
  27. circuitcheck-0.1.0/tests/conftest.py +12 -0
  28. circuitcheck-0.1.0/tests/test_diff.py +175 -0
  29. circuitcheck-0.1.0/tests/test_docs_snippets.py +110 -0
  30. circuitcheck-0.1.0/tests/test_labels.py +156 -0
  31. circuitcheck-0.1.0/tests/test_live_results.py +64 -0
  32. circuitcheck-0.1.0/tests/test_notebooks.py +31 -0
  33. circuitcheck-0.1.0/tests/test_report_cli.py +105 -0
  34. circuitcheck-0.1.0/tests/test_validate.py +131 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 albertlieyingadrian
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,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: circuitcheck
3
+ Version: 0.1.0
4
+ Summary: Tools on top of circuit-tracer: diff attribution graphs across training, validate circuits with controls, and label features cheaply.
5
+ Keywords: interpretability,circuits,attribution-graphs,transcoders,circuit-tracer,autointerp
6
+ Author: albertlieyingadrian
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
+ Classifier: Typing :: Typed
17
+ Requires-Dist: numpy>=1.26
18
+ Requires-Dist: pydantic>=2.7,<3
19
+ Requires-Dist: typer>=0.12
20
+ Requires-Dist: anthropic>=0.69 ; extra == 'anthropic'
21
+ Requires-Dist: pytest>=9.0 ; extra == 'dev'
22
+ Requires-Dist: pytest-cov>=7.0 ; extra == 'dev'
23
+ Requires-Dist: ruff>=0.17 ; extra == 'dev'
24
+ Requires-Dist: mypy>=2.0 ; extra == 'dev'
25
+ Requires-Dist: nbclient>=0.10 ; extra == 'dev'
26
+ Requires-Dist: nbformat>=5.10 ; extra == 'dev'
27
+ Requires-Dist: ipykernel>=6.29 ; extra == 'dev'
28
+ Requires-Dist: openai>=1.100 ; extra == 'openai'
29
+ Requires-Dist: torch>=2.4 ; extra == 'tracer'
30
+ Requires-Dist: transformers>=4.51 ; extra == 'tracer'
31
+ Requires-Python: >=3.11
32
+ Project-URL: Homepage, https://github.com/albertlieyingadrian/circuitcheck
33
+ Project-URL: Source, https://github.com/albertlieyingadrian/circuitcheck
34
+ Project-URL: Documentation, https://github.com/albertlieyingadrian/circuitcheck/tree/main/docs
35
+ Project-URL: Changelog, https://github.com/albertlieyingadrian/circuitcheck/blob/main/CHANGELOG.md
36
+ Provides-Extra: anthropic
37
+ Provides-Extra: dev
38
+ Provides-Extra: openai
39
+ Provides-Extra: tracer
40
+ Description-Content-Type: text/markdown
41
+
42
+ # circuitcheck
43
+
44
+ <p align="center"><img src="docs/images/demo.gif" alt="circuitcheck validate --demo: the toy model's planted switch comes back as a switch, its two readouts as readouts and its redundant pair as backups" width="760"></p>
45
+
46
+ **Test what an attribution graph claims.** circuitcheck is three tools on top of
47
+ [circuit-tracer](https://github.com/decoderesearch/circuit-tracer) attribution graphs:
48
+
49
+ | Tool | Question it answers | Runs without a GPU on |
50
+ |---|---|---|
51
+ | `circuitcheck validate` | Is a group of graph features a **switch** (it causes the behaviour) or a **readout** (it only reflects it)? | the built-in toy model |
52
+ | `circuitcheck diff` | Which features and edges did fine-tuning or RL add or remove, and is the change real? | saved graph summaries |
53
+ | `circuitcheck label` | What does each feature do, in a few words, and how far can that label be trusted? | cached model replies |
54
+
55
+ ▶ [Watch the 2.5-minute walkthrough](docs/videos/walkthrough.mp4) · [Use cases](docs/use-cases.mdx) ·
56
+ [circuitcheck vs circuit-tracer](docs/vs-circuit-tracer.mdx) · [Docs](docs/index.mdx)
57
+
58
+ It grew out of [steerlab's circuits episodes](https://albertlieyingadrian.github.io/steerlab/experiments/#circuits).
59
+ In [a password lock](https://albertlieyingadrian.github.io/steerlab/experiments/lock-circuit/report/) and
60
+ [an RL reward hack](https://albertlieyingadrian.github.io/steerlab/experiments/rl-hack-circuit/report/), the graph's
61
+ most influential features all turned out to be readouts. circuitcheck turns the checks behind that finding into
62
+ reusable code.
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install circuitcheck # after the first PyPI release; until then:
68
+ pip install "git+https://github.com/albertlieyingadrian/circuitcheck"
69
+ # real models: circuit-tracer from GitHub, plus torch
70
+ pip install "git+https://github.com/decoderesearch/circuit-tracer"
71
+ # labels: pip install "circuitcheck[anthropic]" (Claude Haiku 5.5, the default) or "[openai]"
72
+ ```
73
+
74
+ ## Five-minute tour (no GPU, no key)
75
+
76
+ ```bash
77
+ circuitcheck validate --demo --html validate.html
78
+ circuitcheck diff examples/data/rl_hack_graphs.json.gz --before installed/before --after installed/after \
79
+ --control-before control/before --control-after control/after --html diff.html
80
+ ```
81
+
82
+ ```python
83
+ from circuitcheck.validate import logit_diff, validate
84
+ from circuitcheck.validate.toy import demo, demo_nodes
85
+
86
+ backend = demo()
87
+ metric = logit_diff(backend.token_id(" Austin"), backend.token_id(" Sacramento"))
88
+ report = validate(backend, "dallas", demo_nodes(backend), metric=metric, counterfactual="oakland")
89
+ print([(g.name, g.verdict.value) for g in report.groups])
90
+ # [('top-5', 'switch'), ('L5/100@5', 'switch'), ('L7/200@5', 'readout'), ('L8/201@5', 'readout'), ...]
91
+ ```
92
+
93
+ On a real model, `circuitcheck.tracer.TracerBackend` wraps a circuit-tracer `ReplacementModel`:
94
+
95
+ ```python
96
+ from circuit_tracer import ReplacementModel
97
+ from circuitcheck.tracer import TracerBackend
98
+
99
+ model = ReplacementModel.from_pretrained("google/gemma-2-2b", "gemma")
100
+ report = validate(TracerBackend(model), prompt, nodes, metric=metric, counterfactual=other_prompt)
101
+ ```
102
+
103
+ ## What each tool checks
104
+
105
+ **diff.** Graphs of the same prompts before and after training are reduced to per-feature influence and
106
+ feature-to-feature edges, summed over positions. Each feature gets a status (gained, lost, up, down, stable). The
107
+ statuses are backed by:
108
+
109
+ - a paired swap null: before and after labels are swapped at random within each prompt pair, with a
110
+ Benjamini-Hochberg correction across features;
111
+ - a bootstrap interval and a split-half check;
112
+ - optionally, a control run (did the change happen only in the run that learned the behaviour?) and a replication
113
+ seed.
114
+
115
+ The validity check compares replacement and completeness scores, error-node influence and per-layer reconstruction
116
+ error (`circuitcheck.tracer.reconstruction_error`) before and after. The transcoders were trained on the base model,
117
+ and the report says so every time.
118
+
119
+ **validate.** For each group of features:
120
+
121
+ - ablation (set them to 0);
122
+ - steering (multiply them by 3);
123
+ - a counterfactual patch (copy their values from a prompt with a different answer);
124
+ - each of the above on 20 random feature sets matched by layer and position, and on 20 sets matched by write size
125
+ (|activation| x decoder norm).
126
+
127
+ The verdict follows printed rules: switch, partial, backup, nonspecific or readout. An optional explanation swap (Gao's
128
+ test) runs label rules written as code in a checked sandbox. Output is JSON plus an HTML page.
129
+
130
+ **labels.** The pipeline:
131
+
132
+ 1. Explain each feature from its top activating records.
133
+ 2. Score the label on held-out records: detection AUROC (activating and silent excerpts) and, optionally, simulation
134
+ correlation.
135
+ 3. Report calibration: stated confidence against the earned score, and the detector's expected calibration error.
136
+
137
+ Every reply is cached. Labels export in Neuronpedia's explanation format, and Neuronpedia's own labels can be scored by
138
+ the same detector for a fair comparison.
139
+
140
+ ## Results that reproduce the episodes
141
+
142
+ - **Graph diff.** On the RL-hack study's 48 graphs, `diff_graphs` picks the same ten features the study did, in the
143
+ same order. 9 of the 10 are specific to the run that hacked and 6 come back in another seed (test:
144
+ `tests/test_diff.py::test_reproduces_rl_hack_selection`). Split halves of the prompts agree on 70% of the top 10, and
145
+ reconstruction error is unchanged by RL (0.500 vs 0.499).
146
+ - **Labels.** Claude Haiku 5.5 labelled 50 Gemma-2-2B transcoder features for $0.26 in total. Its labels match
147
+ Neuronpedia's on detection (AUROC 0.80 vs 0.78 and 0.80) and beat them on simulation (r = 0.45 vs 0.37 and 0.38).
148
+ The explainer's stated confidence barely predicts its score (r = 0.11), so use the score, not the confidence.
149
+ - **Live validator runs** on the RL-hack model and the password-locked model: see `examples/data/live/`.
150
+
151
+ ## Layout
152
+
153
+ ```
154
+ src/circuitcheck/
155
+ diff/ graphs.py (summaries and loaders: circuit-tracer .pt, Neuronpedia JSON), core.py (the diff)
156
+ validate/ core.py (checks and verdicts), controls.py, metrics.py, sandbox.py, toy.py
157
+ labels/ autointerp.py (explain, detect, simulate, calibrate), providers.py (Claude, OpenAI, cache), neuronpedia.py
158
+ tracer.py circuit-tracer adapter and reconstruction error
159
+ report.py HTML pages
160
+ cli.py the circuitcheck command
161
+ examples/ notebooks 01-03, data/, scripts/ (how the bundled data was made), modal/ (live GPU checks)
162
+ ```
163
+
164
+ ## Development
165
+
166
+ ```bash
167
+ uv venv && uv pip install -e ".[dev]"
168
+ pytest && ruff check && mypy src
169
+ ```
170
+
171
+ MIT licence.
@@ -0,0 +1,130 @@
1
+ # circuitcheck
2
+
3
+ <p align="center"><img src="docs/images/demo.gif" alt="circuitcheck validate --demo: the toy model's planted switch comes back as a switch, its two readouts as readouts and its redundant pair as backups" width="760"></p>
4
+
5
+ **Test what an attribution graph claims.** circuitcheck is three tools on top of
6
+ [circuit-tracer](https://github.com/decoderesearch/circuit-tracer) attribution graphs:
7
+
8
+ | Tool | Question it answers | Runs without a GPU on |
9
+ |---|---|---|
10
+ | `circuitcheck validate` | Is a group of graph features a **switch** (it causes the behaviour) or a **readout** (it only reflects it)? | the built-in toy model |
11
+ | `circuitcheck diff` | Which features and edges did fine-tuning or RL add or remove, and is the change real? | saved graph summaries |
12
+ | `circuitcheck label` | What does each feature do, in a few words, and how far can that label be trusted? | cached model replies |
13
+
14
+ ▶ [Watch the 2.5-minute walkthrough](docs/videos/walkthrough.mp4) · [Use cases](docs/use-cases.mdx) ·
15
+ [circuitcheck vs circuit-tracer](docs/vs-circuit-tracer.mdx) · [Docs](docs/index.mdx)
16
+
17
+ It grew out of [steerlab's circuits episodes](https://albertlieyingadrian.github.io/steerlab/experiments/#circuits).
18
+ In [a password lock](https://albertlieyingadrian.github.io/steerlab/experiments/lock-circuit/report/) and
19
+ [an RL reward hack](https://albertlieyingadrian.github.io/steerlab/experiments/rl-hack-circuit/report/), the graph's
20
+ most influential features all turned out to be readouts. circuitcheck turns the checks behind that finding into
21
+ reusable code.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install circuitcheck # after the first PyPI release; until then:
27
+ pip install "git+https://github.com/albertlieyingadrian/circuitcheck"
28
+ # real models: circuit-tracer from GitHub, plus torch
29
+ pip install "git+https://github.com/decoderesearch/circuit-tracer"
30
+ # labels: pip install "circuitcheck[anthropic]" (Claude Haiku 5.5, the default) or "[openai]"
31
+ ```
32
+
33
+ ## Five-minute tour (no GPU, no key)
34
+
35
+ ```bash
36
+ circuitcheck validate --demo --html validate.html
37
+ circuitcheck diff examples/data/rl_hack_graphs.json.gz --before installed/before --after installed/after \
38
+ --control-before control/before --control-after control/after --html diff.html
39
+ ```
40
+
41
+ ```python
42
+ from circuitcheck.validate import logit_diff, validate
43
+ from circuitcheck.validate.toy import demo, demo_nodes
44
+
45
+ backend = demo()
46
+ metric = logit_diff(backend.token_id(" Austin"), backend.token_id(" Sacramento"))
47
+ report = validate(backend, "dallas", demo_nodes(backend), metric=metric, counterfactual="oakland")
48
+ print([(g.name, g.verdict.value) for g in report.groups])
49
+ # [('top-5', 'switch'), ('L5/100@5', 'switch'), ('L7/200@5', 'readout'), ('L8/201@5', 'readout'), ...]
50
+ ```
51
+
52
+ On a real model, `circuitcheck.tracer.TracerBackend` wraps a circuit-tracer `ReplacementModel`:
53
+
54
+ ```python
55
+ from circuit_tracer import ReplacementModel
56
+ from circuitcheck.tracer import TracerBackend
57
+
58
+ model = ReplacementModel.from_pretrained("google/gemma-2-2b", "gemma")
59
+ report = validate(TracerBackend(model), prompt, nodes, metric=metric, counterfactual=other_prompt)
60
+ ```
61
+
62
+ ## What each tool checks
63
+
64
+ **diff.** Graphs of the same prompts before and after training are reduced to per-feature influence and
65
+ feature-to-feature edges, summed over positions. Each feature gets a status (gained, lost, up, down, stable). The
66
+ statuses are backed by:
67
+
68
+ - a paired swap null: before and after labels are swapped at random within each prompt pair, with a
69
+ Benjamini-Hochberg correction across features;
70
+ - a bootstrap interval and a split-half check;
71
+ - optionally, a control run (did the change happen only in the run that learned the behaviour?) and a replication
72
+ seed.
73
+
74
+ The validity check compares replacement and completeness scores, error-node influence and per-layer reconstruction
75
+ error (`circuitcheck.tracer.reconstruction_error`) before and after. The transcoders were trained on the base model,
76
+ and the report says so every time.
77
+
78
+ **validate.** For each group of features:
79
+
80
+ - ablation (set them to 0);
81
+ - steering (multiply them by 3);
82
+ - a counterfactual patch (copy their values from a prompt with a different answer);
83
+ - each of the above on 20 random feature sets matched by layer and position, and on 20 sets matched by write size
84
+ (|activation| x decoder norm).
85
+
86
+ The verdict follows printed rules: switch, partial, backup, nonspecific or readout. An optional explanation swap (Gao's
87
+ test) runs label rules written as code in a checked sandbox. Output is JSON plus an HTML page.
88
+
89
+ **labels.** The pipeline:
90
+
91
+ 1. Explain each feature from its top activating records.
92
+ 2. Score the label on held-out records: detection AUROC (activating and silent excerpts) and, optionally, simulation
93
+ correlation.
94
+ 3. Report calibration: stated confidence against the earned score, and the detector's expected calibration error.
95
+
96
+ Every reply is cached. Labels export in Neuronpedia's explanation format, and Neuronpedia's own labels can be scored by
97
+ the same detector for a fair comparison.
98
+
99
+ ## Results that reproduce the episodes
100
+
101
+ - **Graph diff.** On the RL-hack study's 48 graphs, `diff_graphs` picks the same ten features the study did, in the
102
+ same order. 9 of the 10 are specific to the run that hacked and 6 come back in another seed (test:
103
+ `tests/test_diff.py::test_reproduces_rl_hack_selection`). Split halves of the prompts agree on 70% of the top 10, and
104
+ reconstruction error is unchanged by RL (0.500 vs 0.499).
105
+ - **Labels.** Claude Haiku 5.5 labelled 50 Gemma-2-2B transcoder features for $0.26 in total. Its labels match
106
+ Neuronpedia's on detection (AUROC 0.80 vs 0.78 and 0.80) and beat them on simulation (r = 0.45 vs 0.37 and 0.38).
107
+ The explainer's stated confidence barely predicts its score (r = 0.11), so use the score, not the confidence.
108
+ - **Live validator runs** on the RL-hack model and the password-locked model: see `examples/data/live/`.
109
+
110
+ ## Layout
111
+
112
+ ```
113
+ src/circuitcheck/
114
+ diff/ graphs.py (summaries and loaders: circuit-tracer .pt, Neuronpedia JSON), core.py (the diff)
115
+ validate/ core.py (checks and verdicts), controls.py, metrics.py, sandbox.py, toy.py
116
+ labels/ autointerp.py (explain, detect, simulate, calibrate), providers.py (Claude, OpenAI, cache), neuronpedia.py
117
+ tracer.py circuit-tracer adapter and reconstruction error
118
+ report.py HTML pages
119
+ cli.py the circuitcheck command
120
+ examples/ notebooks 01-03, data/, scripts/ (how the bundled data was made), modal/ (live GPU checks)
121
+ ```
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ uv venv && uv pip install -e ".[dev]"
127
+ pytest && ruff check && mypy src
128
+ ```
129
+
130
+ MIT licence.
@@ -0,0 +1,134 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11.7,<0.14"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "circuitcheck"
7
+ version = "0.1.0"
8
+ description = "Tools on top of circuit-tracer: diff attribution graphs across training, validate circuits with controls, and label features cheaply."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ keywords = [
14
+ "interpretability",
15
+ "circuits",
16
+ "attribution-graphs",
17
+ "transcoders",
18
+ "circuit-tracer",
19
+ "autointerp",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 2 - Pre-Alpha",
23
+ "Intended Audience :: Science/Research",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = [
32
+ "numpy>=1.26",
33
+ "pydantic>=2.7,<3",
34
+ "typer>=0.12",
35
+ ]
36
+
37
+ [[project.authors]]
38
+ name = "albertlieyingadrian"
39
+
40
+ [project.optional-dependencies]
41
+ tracer = [
42
+ "torch>=2.4",
43
+ "transformers>=4.51",
44
+ ]
45
+ anthropic = ["anthropic>=0.69"]
46
+ openai = ["openai>=1.100"]
47
+ dev = [
48
+ "pytest>=9.0",
49
+ "pytest-cov>=7.0",
50
+ "ruff>=0.17",
51
+ "mypy>=2.0",
52
+ "nbclient>=0.10",
53
+ "nbformat>=5.10",
54
+ "ipykernel>=6.29",
55
+ ]
56
+
57
+ [project.scripts]
58
+ circuitcheck = "circuitcheck.cli:app"
59
+
60
+ [project.urls]
61
+ Homepage = "https://github.com/albertlieyingadrian/circuitcheck"
62
+ Source = "https://github.com/albertlieyingadrian/circuitcheck"
63
+ Documentation = "https://github.com/albertlieyingadrian/circuitcheck/tree/main/docs"
64
+ Changelog = "https://github.com/albertlieyingadrian/circuitcheck/blob/main/CHANGELOG.md"
65
+
66
+ [dependency-groups]
67
+ dev = [
68
+ "pytest>=9.0",
69
+ "pytest-cov>=7.0",
70
+ "ruff>=0.17",
71
+ "mypy>=2.0",
72
+ ]
73
+
74
+ [tool.uv.build-backend]
75
+ module-name = "circuitcheck"
76
+ source-include = ["tests/**"]
77
+
78
+ [tool.pytest.ini_options]
79
+ testpaths = ["tests"]
80
+ addopts = "-ra --strict-markers --strict-config -m 'not slow'"
81
+ markers = ["slow: real-model or network runs, excluded by default (run with -m slow)"]
82
+
83
+ [tool.ruff]
84
+ line-length = 120
85
+ target-version = "py311"
86
+ extend-exclude = [
87
+ ".agents",
88
+ ".claude",
89
+ ]
90
+
91
+ [tool.ruff.lint]
92
+ select = [
93
+ "E",
94
+ "F",
95
+ "W",
96
+ "I",
97
+ "B",
98
+ "UP",
99
+ "SIM",
100
+ "RUF",
101
+ ]
102
+ ignore = [
103
+ "RUF001",
104
+ "RUF002",
105
+ "RUF003",
106
+ ]
107
+
108
+ [tool.mypy]
109
+ python_version = "3.11"
110
+ strict = true
111
+ plugins = ["pydantic.mypy"]
112
+
113
+ [[tool.mypy.overrides]]
114
+ module = [
115
+ "torch",
116
+ "torch.*",
117
+ "transformers",
118
+ "transformers.*",
119
+ "circuit_tracer",
120
+ "circuit_tracer.*",
121
+ "anthropic",
122
+ "anthropic.*",
123
+ "openai",
124
+ "openai.*",
125
+ ]
126
+ ignore_missing_imports = true
127
+
128
+ [tool.coverage.run]
129
+ source = ["circuitcheck"]
130
+ branch = true
131
+
132
+ [tool.coverage.report]
133
+ show_missing = true
134
+ skip_covered = true
@@ -0,0 +1,95 @@
1
+ [build-system]
2
+ # Keep the upper bound: uv_build follows uv's versioning and may change between minors.
3
+ requires = ["uv_build>=0.11.7,<0.14"]
4
+ build-backend = "uv_build"
5
+
6
+ [project]
7
+ name = "circuitcheck"
8
+ # The ONLY place the version lives. Code reads it with importlib.metadata.
9
+ version = "0.1.0"
10
+ description = "Tools on top of circuit-tracer: diff attribution graphs across training, validate circuits with controls, and label features cheaply."
11
+ readme = "README.md"
12
+ requires-python = ">=3.11"
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ authors = [{ name = "albertlieyingadrian" }]
16
+ keywords = ["interpretability", "circuits", "attribution-graphs", "transcoders", "circuit-tracer", "autointerp"]
17
+ classifiers = [
18
+ "Development Status :: 2 - Pre-Alpha",
19
+ "Intended Audience :: Science/Research",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
25
+ "Typing :: Typed",
26
+ ]
27
+ # The base install stays light: no torch. Everything runs on saved graphs, the toy model or cached labels.
28
+ dependencies = [
29
+ "numpy>=1.26",
30
+ "pydantic>=2.7,<3",
31
+ "typer>=0.12",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ # circuit-tracer is installed from GitHub (it is not on PyPI): see the README.
36
+ tracer = ["torch>=2.4", "transformers>=4.51"]
37
+ anthropic = ["anthropic>=0.69"]
38
+ openai = ["openai>=1.100"]
39
+ dev = ["pytest>=9.0", "pytest-cov>=7.0", "ruff>=0.17", "mypy>=2.0", "nbclient>=0.10", "nbformat>=5.10", "ipykernel>=6.29"]
40
+
41
+ [project.scripts]
42
+ circuitcheck = "circuitcheck.cli:app"
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/albertlieyingadrian/circuitcheck"
46
+ Source = "https://github.com/albertlieyingadrian/circuitcheck"
47
+ Documentation = "https://github.com/albertlieyingadrian/circuitcheck/tree/main/docs"
48
+ Changelog = "https://github.com/albertlieyingadrian/circuitcheck/blob/main/CHANGELOG.md"
49
+
50
+ [dependency-groups]
51
+ dev = [
52
+ "pytest>=9.0",
53
+ "pytest-cov>=7.0",
54
+ "ruff>=0.17",
55
+ "mypy>=2.0",
56
+ ]
57
+
58
+ [tool.uv.build-backend]
59
+ module-name = "circuitcheck"
60
+ # The wheel ships only src/circuitcheck; the sdist also carries the tests.
61
+ source-include = ["tests/**"]
62
+
63
+ [tool.pytest.ini_options]
64
+ testpaths = ["tests"]
65
+ addopts = "-ra --strict-markers --strict-config -m 'not slow'"
66
+ markers = [
67
+ "slow: real-model or network runs, excluded by default (run with -m slow)",
68
+ ]
69
+
70
+ [tool.ruff]
71
+ line-length = 120
72
+ target-version = "py311"
73
+ # Agent skills are third-party tooling, not this project's code.
74
+ extend-exclude = [".agents", ".claude"]
75
+
76
+ [tool.ruff.lint]
77
+ select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF"]
78
+ ignore = ["RUF001", "RUF002", "RUF003"]
79
+
80
+ [tool.mypy]
81
+ python_version = "3.11"
82
+ strict = true
83
+ plugins = ["pydantic.mypy"]
84
+
85
+ [[tool.mypy.overrides]]
86
+ module = ["torch", "torch.*", "transformers", "transformers.*", "circuit_tracer", "circuit_tracer.*", "anthropic", "anthropic.*", "openai", "openai.*"]
87
+ ignore_missing_imports = true
88
+
89
+ [tool.coverage.run]
90
+ source = ["circuitcheck"]
91
+ branch = true
92
+
93
+ [tool.coverage.report]
94
+ show_missing = true
95
+ skip_covered = true
@@ -0,0 +1,16 @@
1
+ """circuitcheck: tools on top of circuit-tracer.
2
+
3
+ - `circuitcheck.diff`: compare attribution graphs before and after fine-tuning or RL;
4
+ - `circuitcheck.validate`: test whether graph features are a switch or a readout, against random and matched-norm
5
+ controls;
6
+ - `circuitcheck.labels`: cheap automatic feature labels with detection and simulation scores;
7
+ - `circuitcheck.tracer`: the circuit-tracer adapter (needs torch and circuit-tracer);
8
+ - `circuitcheck.report`: HTML pages for all three.
9
+ """
10
+
11
+ from importlib.metadata import PackageNotFoundError, version
12
+
13
+ try:
14
+ __version__ = version("circuitcheck")
15
+ except PackageNotFoundError: # pragma: no cover
16
+ __version__ = "0.0.0+local"