rulereach-delegate 0.1.1__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 (45) hide show
  1. rulereach_delegate-0.1.1/.github/workflows/ci.yml +28 -0
  2. rulereach_delegate-0.1.1/.github/workflows/release.yml +58 -0
  3. rulereach_delegate-0.1.1/.gitignore +7 -0
  4. rulereach_delegate-0.1.1/.markdownlint-cli2.jsonc +18 -0
  5. rulereach_delegate-0.1.1/.pre-commit-config.yaml +20 -0
  6. rulereach_delegate-0.1.1/AGENTS.md +21 -0
  7. rulereach_delegate-0.1.1/CHANGELOG.md +31 -0
  8. rulereach_delegate-0.1.1/CLAUDE.md +5 -0
  9. rulereach_delegate-0.1.1/CONTRIBUTING.md +31 -0
  10. rulereach_delegate-0.1.1/LICENSE +21 -0
  11. rulereach_delegate-0.1.1/PKG-INFO +204 -0
  12. rulereach_delegate-0.1.1/README.md +173 -0
  13. rulereach_delegate-0.1.1/assets/demo.gif +0 -0
  14. rulereach_delegate-0.1.1/docs/README.es.md +65 -0
  15. rulereach_delegate-0.1.1/docs/README.pt-BR.md +64 -0
  16. rulereach_delegate-0.1.1/docs/README.ru.md +63 -0
  17. rulereach_delegate-0.1.1/docs/README.zh-CN.md +57 -0
  18. rulereach_delegate-0.1.1/docs/semantics.md +117 -0
  19. rulereach_delegate-0.1.1/pyproject.toml +78 -0
  20. rulereach_delegate-0.1.1/scripts/check.sh +37 -0
  21. rulereach_delegate-0.1.1/scripts/demo_gif.py +207 -0
  22. rulereach_delegate-0.1.1/src/rulereach_delegate/__init__.py +7 -0
  23. rulereach_delegate-0.1.1/src/rulereach_delegate/__main__.py +8 -0
  24. rulereach_delegate-0.1.1/src/rulereach_delegate/checks.py +447 -0
  25. rulereach_delegate-0.1.1/src/rulereach_delegate/cli.py +149 -0
  26. rulereach_delegate-0.1.1/src/rulereach_delegate/config.py +109 -0
  27. rulereach_delegate-0.1.1/src/rulereach_delegate/discovery.py +262 -0
  28. rulereach_delegate-0.1.1/src/rulereach_delegate/model.py +156 -0
  29. rulereach_delegate-0.1.1/src/rulereach_delegate/report.py +193 -0
  30. rulereach_delegate-0.1.1/src/rulereach_delegate/startup.py +114 -0
  31. rulereach_delegate-0.1.1/src/rulereach_delegate/tools.py +134 -0
  32. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/agents/narrowed.md +10 -0
  33. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/agents/no-description.md +5 -0
  34. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/agents/unparsable.md +6 -0
  35. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/agents/zero-tools.md +7 -0
  36. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/rules/testing.md +5 -0
  37. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/skills/deep-research/SKILL.md +9 -0
  38. rulereach_delegate-0.1.1/tests/fixtures/broken/.claude/skills/legacy-helper/SKILL.md +8 -0
  39. rulereach_delegate-0.1.1/tests/fixtures/broken/CLAUDE.md +5 -0
  40. rulereach_delegate-0.1.1/tests/fixtures/broken/docs/style.md +1 -0
  41. rulereach_delegate-0.1.1/tests/fixtures/clean/.claude/agents/reviewer.md +10 -0
  42. rulereach_delegate-0.1.1/tests/fixtures/clean/.claude/skills/api-conventions/SKILL.md +6 -0
  43. rulereach_delegate-0.1.1/tests/fixtures/clean/CLAUDE.md +4 -0
  44. rulereach_delegate-0.1.1/tests/test_rulereach_delegate.py +228 -0
  45. rulereach_delegate-0.1.1/uv.lock +1152 -0
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ check:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ python-version: ["3.10", "3.12"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: astral-sh/setup-uv@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+ - run: uv pip install --system -e . pytest ruff==0.16.0 mypy==2.3.0 types-PyYAML
24
+ - run: ruff check .
25
+ - run: ruff format --check .
26
+ - run: mypy
27
+ - run: pytest -q
28
+ - run: rulereach-delegate check . --exclude "tests/fixtures/**"
@@ -0,0 +1,58 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: astral-sh/setup-uv@v4
16
+ - name: Check tag matches project version
17
+ run: |
18
+ tag="${GITHUB_REF_NAME#v}"
19
+ version="$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)"
20
+ if [ "$tag" != "$version" ]; then
21
+ echo "tag $tag does not match pyproject version $version"
22
+ exit 1
23
+ fi
24
+ - name: Build sdist and wheel
25
+ run: uv build
26
+ - uses: actions/upload-artifact@v4
27
+ with:
28
+ name: dist
29
+ path: dist/
30
+
31
+ pypi:
32
+ needs: build
33
+ runs-on: ubuntu-latest
34
+ environment: pypi
35
+ permissions:
36
+ id-token: write
37
+ steps:
38
+ - uses: actions/download-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/
42
+ - uses: pypa/gh-action-pypi-publish@release/v1
43
+
44
+ github-release:
45
+ needs: pypi
46
+ runs-on: ubuntu-latest
47
+ permissions:
48
+ contents: write
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ - uses: actions/download-artifact@v4
52
+ with:
53
+ name: dist
54
+ path: dist/
55
+ - name: Create GitHub release
56
+ env:
57
+ GH_TOKEN: ${{ github.token }}
58
+ run: gh release create "$GITHUB_REF_NAME" dist/* --title "$GITHUB_REF_NAME" --generate-notes
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ .mypy_cache/
6
+ .pytest_cache/
7
+ .ruff_cache/
@@ -0,0 +1,18 @@
1
+ {
2
+ "config": {
3
+ "MD013": false,
4
+ "MD033": false,
5
+ "MD012": false,
6
+ "MD036": false
7
+ },
8
+ // CLAUDE.md starts with an @AGENTS.md import, which is the documented way to keep one
9
+ // canonical instruction file, so MD041 does not apply to it.
10
+ "ignores": [
11
+ ".venv/**",
12
+ "tests/fixtures/**",
13
+ "CHANGELOG.md",
14
+ "CLAUDE.md",
15
+ "lychee-*/**",
16
+ "gitleaks*/**"
17
+ ]
18
+ }
@@ -0,0 +1,20 @@
1
+ default_language_version:
2
+ python: python3.12
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.16.0
6
+ hooks:
7
+ - id: ruff-check
8
+ args: [--fix]
9
+ - id: ruff-format
10
+ - repo: https://github.com/pre-commit/mirrors-mypy
11
+ rev: v2.3.0
12
+ hooks:
13
+ - id: mypy
14
+ additional_dependencies: [types-PyYAML]
15
+ - repo: https://github.com/pre-commit/pre-commit-hooks
16
+ rev: v6.0.0
17
+ hooks:
18
+ - id: trailing-whitespace
19
+ - id: end-of-file-fixer
20
+ - id: check-yaml
@@ -0,0 +1,21 @@
1
+ # rulereach-delegate
2
+
3
+ A CLI that audits what reaches a Claude Code subagent. Python, PyYAML is the only runtime
4
+ dependency.
5
+
6
+ ## Commands
7
+
8
+ - `uv sync --extra dev` to set up.
9
+ - `bash scripts/check.sh` is the full gate and must pass before a commit.
10
+ - `uv run python -m pytest -q` for tests alone.
11
+
12
+ ## Conventions
13
+
14
+ - Every check cites the documentation sentence that defines the behaviour, recorded in
15
+ `docs/semantics.md` with the date it was read. Never guess a runtime rule.
16
+ - Findings say what a definition loses at delegation, not how the file is written.
17
+ - Fixtures under `tests/fixtures/` are real directory trees; add a case there for every new
18
+ check, and keep `tests/fixtures/clean/` free of findings.
19
+ - A heuristic that fires on prose is a bug. Check new heuristics against large public
20
+ collections of subagents before shipping them.
21
+ - Keep functions small and typed; mypy runs in strict mode.
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses
5
+ [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.1] - 2026-08-26
8
+
9
+ First release published to PyPI. No functional changes: the `0.1.0` tag was built
10
+ before the PyPI trusted publisher existed, so the upload never happened.
11
+
12
+ ## [0.1.0] - 2026-08-26
13
+
14
+ First release.
15
+
16
+ ### Added
17
+
18
+ - `check`: fourteen checks over `.claude/agents/`, plugin `agents/` directories and forking
19
+ skills, covering files Claude Code skips, the two documented tool filters, preloaded skills
20
+ and `context: fork` targets. Exit code 1 on errors, `--strict` to fail on warnings too.
21
+ - `list`: every subagent and forking skill, with the agent type it runs as, whether it loads
22
+ the `CLAUDE.md` hierarchy, and how many tools survive the filters.
23
+ - `explain`: the documented startup composition of one subagent, split into what reaches it
24
+ and what does not.
25
+ - `--json` on every command, `--exclude` for fixture directories, `--check` to run one check.
26
+ - Configuration through `[tool.rulereach-delegate]` in `pyproject.toml` or
27
+ `.rulereach-delegate.toml`.
28
+ - `docs/semantics.md`: the documentation sentences every check is built on, with the date they
29
+ were read.
30
+
31
+ [0.1.0]: https://github.com/Topicspot/rulereach-delegate/releases/tag/v0.1.0
@@ -0,0 +1,5 @@
1
+ @AGENTS.md
2
+
3
+ ## Claude Code
4
+
5
+ Read `docs/semantics.md` before touching `src/rulereach_delegate/checks.py`.
@@ -0,0 +1,31 @@
1
+ # Contributing
2
+
3
+ Thanks for taking the time. Small, focused pull requests are the easiest to merge.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ uv sync --extra dev
9
+ uv run python -m pytest -q
10
+ ```
11
+
12
+ `bash scripts/check.sh` runs the full gate: ruff, mypy in strict mode, pytest, vulture,
13
+ pip-audit, markdownlint, the tool on itself, and, when they are installed, gitleaks and
14
+ lychee. CI runs a subset of the same commands, so a green local gate means a green CI.
15
+
16
+ ## Adding a check
17
+
18
+ 1. Find the sentence in the Claude Code documentation that defines the behaviour, and add it
19
+ to `docs/semantics.md` with the date you read it. A check without a source does not land:
20
+ guessing a runtime rule is how a linter starts lying.
21
+ 2. Add a directory tree under `tests/fixtures/broken/` that triggers it, and make sure
22
+ `tests/fixtures/clean/` stays clean.
23
+ 3. Write the finding so it says what the definition loses, not how the file is written.
24
+ Message, one-line fix, documentation URL.
25
+ 4. Run the tool over a few large public collections of subagents before you open the pull
26
+ request. A check that fires on prose is worse than no check.
27
+
28
+ ## Reporting a false positive
29
+
30
+ Open an issue with the smallest agent or skill file that reproduces it and the command you
31
+ ran. False positives are treated as bugs, not as opinions.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Topicspot
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,204 @@
1
+ Metadata-Version: 2.5
2
+ Name: rulereach-delegate
3
+ Version: 0.1.1
4
+ Summary: Audit what reaches a Claude Code subagent: instructions, skills and tools that delegation drops without an error.
5
+ Project-URL: Homepage, https://github.com/Topicspot/rulereach-delegate
6
+ Project-URL: Repository, https://github.com/Topicspot/rulereach-delegate
7
+ Project-URL: Issues, https://github.com/Topicspot/rulereach-delegate/issues
8
+ Project-URL: Changelog, https://github.com/Topicspot/rulereach-delegate/blob/main/CHANGELOG.md
9
+ Author: Topicspot
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent-skills,claude-code,developer-tools,lint,subagents
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: Software Development :: Quality Assurance
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: pyyaml>=6.0
21
+ Requires-Dist: tomli>=2.0.1; python_version < '3.11'
22
+ Provides-Extra: dev
23
+ Requires-Dist: mypy==2.3.0; extra == 'dev'
24
+ Requires-Dist: pillow>=11; extra == 'dev'
25
+ Requires-Dist: pip-audit>=2.7; extra == 'dev'
26
+ Requires-Dist: pytest>=9.0; extra == 'dev'
27
+ Requires-Dist: ruff==0.16.0; extra == 'dev'
28
+ Requires-Dist: types-pyyaml; extra == 'dev'
29
+ Requires-Dist: vulture>=2.16; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # rulereach-delegate
33
+
34
+ **English** · [Русский](docs/README.ru.md) · [简体中文](docs/README.zh-CN.md) · [Español](docs/README.es.md) · [Português](docs/README.pt-BR.md)
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/rulereach-delegate?style=flat-square&label=pypi&color=3775A9)](https://pypi.org/project/rulereach-delegate/)
37
+ [![Python](https://img.shields.io/pypi/pyversions/rulereach-delegate?style=flat-square&color=4B8BBE)](https://pypi.org/project/rulereach-delegate/)
38
+ [![CI](https://github.com/Topicspot/rulereach-delegate/actions/workflows/ci.yml/badge.svg)](https://github.com/Topicspot/rulereach-delegate/actions/workflows/ci.yml)
39
+ [![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](https://github.com/Topicspot/rulereach-delegate/blob/main/LICENSE)
40
+
41
+ A subagent definition is a promise about a fresh context window: this prompt, these tools,
42
+ these skills. Claude Code keeps part of that promise and quietly rewrites the rest. A
43
+ background subagent, which is the default, keeps only a fixed list of built-in tools, so
44
+ `BashOutput` in your `tools` list is dropped with no error. A `tools` list that survives
45
+ none of the filters makes the agent fail to launch. A skill named in the prompt but missing
46
+ from the `skills` field is not in the context at startup. A skill that forks into `Explore`
47
+ sees no `CLAUDE.md` at all. An `agent:` that does not resolve falls back to a general-purpose
48
+ agent with a wider tool pool than the one you asked for.
49
+
50
+ `rulereach-delegate` reads `.claude/agents/`, plugin `agents/` directories and every
51
+ `SKILL.md` in a repository, applies the documented startup and tool-filter rules, and reports
52
+ what delegation drops. It runs offline and cites the documentation page behind every finding.
53
+
54
+ ![rulereach-delegate demo](https://raw.githubusercontent.com/Topicspot/rulereach-delegate/main/assets/demo.gif)
55
+
56
+ ```console
57
+ $ rulereach-delegate check
58
+ .claude/agents/narrowed.md
59
+ x skill-unreachable the prompt mentions the 'deep-research' skill, but it is not preloaded and the agent has no Skill tool
60
+ fix: add deep-research to the skills field, or add Skill to tools
61
+ docs: https://code.claude.com/docs/en/sub-agents#preload-skills-into-subagents
62
+ ! tools-background-removed BashOutput is dropped for a background subagent, which is the default, and the removal reports no error
63
+ fix: keep the agent in the foreground for this work, or drop the tool from the list so the definition says what the agent really gets
64
+ docs: https://code.claude.com/docs/en/sub-agents#available-tools
65
+ .claude/agents/zero-tools.md
66
+ x tools-zero no entry in tools survives the documented filters, so the agent fails to launch
67
+ fix: list tools the agent can actually keep, such as Artifact, Bash, Edit, EnterWorktree
68
+ docs: https://code.claude.com/docs/en/errors#agent-would-be-spawned-with-zero-tools
69
+ .claude/skills/deep-research/SKILL.md
70
+ ! fork-skips-memory agent: Explore skips the CLAUDE.md hierarchy, so 4 instruction line(s) in it, 3 of them prohibitions, do not reach this fork
71
+ fix: restate the rules this task depends on inside the skill, or fork into an agent that loads CLAUDE.md
72
+ docs: https://code.claude.com/docs/en/sub-agents#what-loads-at-startup
73
+
74
+ rulereach-delegate: 5 error(s), 5 warning(s), 2 note(s)
75
+ ```
76
+
77
+ ## Install
78
+
79
+ ```bash
80
+ pipx install rulereach-delegate # or: uv tool install rulereach-delegate
81
+ ```
82
+
83
+ Nothing is sent anywhere: the tool reads files and exits. No API keys, no network calls.
84
+
85
+ ## Use
86
+
87
+ ```bash
88
+ rulereach-delegate check # report what delegation loses, exit 1 on errors
89
+ rulereach-delegate check --strict # exit 1 on warnings and notes too
90
+ rulereach-delegate check --check tools-zero # one check at a time
91
+ rulereach-delegate check --exclude "tests/fixtures/**"
92
+ rulereach-delegate list # every subagent and forking skill
93
+ rulereach-delegate explain code-reviewer # what that agent starts with
94
+ ```
95
+
96
+ `explain` is the answer to "why did the subagent ignore that":
97
+
98
+ ```console
99
+ $ rulereach-delegate explain deep-research
100
+ deep-research (.claude/skills/deep-research/SKILL.md, forking skill)
101
+
102
+ Reaches it at startup:
103
+ - its own system prompt: the skill content, injected as the task
104
+
105
+ Does not reach it:
106
+ - the CLAUDE.md hierarchy: 4 instruction line(s), 3 of them prohibitions, and the git status snapshot
107
+ - the parent conversation history and the files already read
108
+ - skills invoked in the parent session, unless named in the skills field
109
+ - the output style and the parent's auto memory
110
+
111
+ Tools: inherits every tool available to subagents.
112
+ Runs in the background (the default); a background subagent keeps only a fixed set of built-in tools, 19 of them, plus every MCP tool.
113
+ ```
114
+
115
+ Add `--json` to any command for machine-readable output.
116
+
117
+ ## Checks
118
+
119
+ | ID | What it catches |
120
+ | --- | --- |
121
+ | `not-loaded` | agent file Claude Code skips: unparsable frontmatter, no `name`, a `name` with a colon or leading hyphen, or a `name` with no `description` |
122
+ | `unknown-field` | frontmatter key that is not a subagent field, such as a skill's `allowed-tools`, so it is ignored |
123
+ | `tools-removed` | tool removed from every subagent even when listed, such as `AskUserQuestion` or `ExitPlanMode` outside plan mode |
124
+ | `tools-background-removed` | built-in tool a background subagent does not keep, dropped without an error |
125
+ | `tools-zero` | no entry in `tools` survives the filters, so the agent fails to launch |
126
+ | `tools-denied-conflict` | tool in both `tools` and `disallowedTools`, so it is denied |
127
+ | `skill-missing` | `skills` names a skill that is not in the repository |
128
+ | `skill-not-preloadable` | `skills` names a skill with `disable-model-invocation: true`, which cannot be preloaded |
129
+ | `skill-unreachable` | prompt names a skill that is neither preloaded nor reachable, because the agent has no `Skill` tool |
130
+ | `skill-not-preloaded` | prompt names a skill the agent must discover itself instead of starting with its content |
131
+ | `fork-agent-unresolved` | `agent:` in a forking skill that resolves to nothing, so the fork runs general-purpose with a wider tool pool |
132
+ | `fork-skips-memory` | fork into `Explore` or `Plan`, which skip the `CLAUDE.md` hierarchy and git status |
133
+ | `fork-background-tools` | tool pre-approved in `allowed-tools` that a background fork does not have |
134
+ | `model-unknown` | `model` that is neither an alias nor a full model ID |
135
+
136
+ Severity is about consequence, not style. An error means the definition cannot do what it
137
+ says: the agent does not load, does not launch, or loses a capability it names. A warning
138
+ means it silently gets less than the file promises. A note is behaviour worth knowing that is
139
+ not a mistake.
140
+
141
+ The documented sentences each check is built on are collected in
142
+ [docs/semantics.md](docs/semantics.md), with the date they were read.
143
+
144
+ ## Scope
145
+
146
+ Claude Code only, and only what a repository can carry: `.claude/agents/`, plugin `agents/`
147
+ directories, `.claude/skills/*/SKILL.md`, the `CLAUDE.md` hierarchy with its imports, and
148
+ `.claude/rules/`. Subagents installed at user scope in `~/.claude/agents/` are outside a
149
+ repository, so they are outside a repository check. Runtime behaviour is out of scope too:
150
+ this is a static audit of definitions, not a transcript analyser.
151
+
152
+ ## Configuration
153
+
154
+ Optional. Put the flags you would otherwise repeat into `pyproject.toml`:
155
+
156
+ ```toml
157
+ [tool.rulereach-delegate]
158
+ exclude = ["tests/fixtures/**"]
159
+ strict = false
160
+ ```
161
+
162
+ Projects without a `pyproject.toml` can use a `.rulereach-delegate.toml` with the same keys at
163
+ the top level. If both exist, `.rulereach-delegate.toml` wins, and command line flags win over
164
+ both. An unreadable file, an unknown key or a value of the wrong type is reported on stderr
165
+ rather than ignored.
166
+
167
+ ## In CI
168
+
169
+ ```yaml
170
+ - name: rulereach-delegate
171
+ run: uvx rulereach-delegate check
172
+ ```
173
+
174
+ `check` exits 1 when there is at least one error, 0 otherwise. Use `--strict` to fail on
175
+ warnings as well.
176
+
177
+ ## Alternatives
178
+
179
+ - [skilldoctor](https://github.com/studiomeyer-io/skilldoctor), [skillcheck](https://github.com/erphq/skillcheck),
180
+ [claudelint](https://github.com/pdugan20/claudelint) and
181
+ [claude-plugins-validation](https://github.com/Emasoft/claude-plugins-validation) validate
182
+ the shape of skill, `CLAUDE.md` and subagent files: frontmatter schema, referenced paths,
183
+ security patterns. Some of them check a subagent's frontmatter fields as well. They stop at
184
+ the file; this tool continues into what the runtime does to it, which is where the tool
185
+ filters and the startup composition live.
186
+ - [rule-trace](https://github.com/seanleecoder/rule-trace) answers the same question at
187
+ runtime: it asks the agent to disclose which rules it applied, and counts those disclosures
188
+ over time. That needs your rules migrated into its format and a hook wired up. This tool is
189
+ static and needs nothing but the repository.
190
+ - `claude plugin validate` finds agent files whose frontmatter does not parse. It does not
191
+ flag a file that parses but has no `name`, and it does not model the tool filters.
192
+
193
+ ## Related
194
+
195
+ - [rulereach](https://github.com/Topicspot/rulereach) - whether an instruction file reaches
196
+ the main agent at all: Codex, Claude Code, Cursor, Copilot.
197
+ - [skillfrisk](https://github.com/Topicspot/skillfrisk) - scan agent skills and MCP servers
198
+ for prompt injection and unsafe instructions.
199
+ - [ciparity](https://github.com/Topicspot/ciparity) - find drift between pre-commit hooks
200
+ and your CI pipeline.
201
+
202
+ ## License
203
+
204
+ MIT
@@ -0,0 +1,173 @@
1
+ # rulereach-delegate
2
+
3
+ **English** · [Русский](docs/README.ru.md) · [简体中文](docs/README.zh-CN.md) · [Español](docs/README.es.md) · [Português](docs/README.pt-BR.md)
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/rulereach-delegate?style=flat-square&label=pypi&color=3775A9)](https://pypi.org/project/rulereach-delegate/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/rulereach-delegate?style=flat-square&color=4B8BBE)](https://pypi.org/project/rulereach-delegate/)
7
+ [![CI](https://github.com/Topicspot/rulereach-delegate/actions/workflows/ci.yml/badge.svg)](https://github.com/Topicspot/rulereach-delegate/actions/workflows/ci.yml)
8
+ [![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](https://github.com/Topicspot/rulereach-delegate/blob/main/LICENSE)
9
+
10
+ A subagent definition is a promise about a fresh context window: this prompt, these tools,
11
+ these skills. Claude Code keeps part of that promise and quietly rewrites the rest. A
12
+ background subagent, which is the default, keeps only a fixed list of built-in tools, so
13
+ `BashOutput` in your `tools` list is dropped with no error. A `tools` list that survives
14
+ none of the filters makes the agent fail to launch. A skill named in the prompt but missing
15
+ from the `skills` field is not in the context at startup. A skill that forks into `Explore`
16
+ sees no `CLAUDE.md` at all. An `agent:` that does not resolve falls back to a general-purpose
17
+ agent with a wider tool pool than the one you asked for.
18
+
19
+ `rulereach-delegate` reads `.claude/agents/`, plugin `agents/` directories and every
20
+ `SKILL.md` in a repository, applies the documented startup and tool-filter rules, and reports
21
+ what delegation drops. It runs offline and cites the documentation page behind every finding.
22
+
23
+ ![rulereach-delegate demo](https://raw.githubusercontent.com/Topicspot/rulereach-delegate/main/assets/demo.gif)
24
+
25
+ ```console
26
+ $ rulereach-delegate check
27
+ .claude/agents/narrowed.md
28
+ x skill-unreachable the prompt mentions the 'deep-research' skill, but it is not preloaded and the agent has no Skill tool
29
+ fix: add deep-research to the skills field, or add Skill to tools
30
+ docs: https://code.claude.com/docs/en/sub-agents#preload-skills-into-subagents
31
+ ! tools-background-removed BashOutput is dropped for a background subagent, which is the default, and the removal reports no error
32
+ fix: keep the agent in the foreground for this work, or drop the tool from the list so the definition says what the agent really gets
33
+ docs: https://code.claude.com/docs/en/sub-agents#available-tools
34
+ .claude/agents/zero-tools.md
35
+ x tools-zero no entry in tools survives the documented filters, so the agent fails to launch
36
+ fix: list tools the agent can actually keep, such as Artifact, Bash, Edit, EnterWorktree
37
+ docs: https://code.claude.com/docs/en/errors#agent-would-be-spawned-with-zero-tools
38
+ .claude/skills/deep-research/SKILL.md
39
+ ! fork-skips-memory agent: Explore skips the CLAUDE.md hierarchy, so 4 instruction line(s) in it, 3 of them prohibitions, do not reach this fork
40
+ fix: restate the rules this task depends on inside the skill, or fork into an agent that loads CLAUDE.md
41
+ docs: https://code.claude.com/docs/en/sub-agents#what-loads-at-startup
42
+
43
+ rulereach-delegate: 5 error(s), 5 warning(s), 2 note(s)
44
+ ```
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pipx install rulereach-delegate # or: uv tool install rulereach-delegate
50
+ ```
51
+
52
+ Nothing is sent anywhere: the tool reads files and exits. No API keys, no network calls.
53
+
54
+ ## Use
55
+
56
+ ```bash
57
+ rulereach-delegate check # report what delegation loses, exit 1 on errors
58
+ rulereach-delegate check --strict # exit 1 on warnings and notes too
59
+ rulereach-delegate check --check tools-zero # one check at a time
60
+ rulereach-delegate check --exclude "tests/fixtures/**"
61
+ rulereach-delegate list # every subagent and forking skill
62
+ rulereach-delegate explain code-reviewer # what that agent starts with
63
+ ```
64
+
65
+ `explain` is the answer to "why did the subagent ignore that":
66
+
67
+ ```console
68
+ $ rulereach-delegate explain deep-research
69
+ deep-research (.claude/skills/deep-research/SKILL.md, forking skill)
70
+
71
+ Reaches it at startup:
72
+ - its own system prompt: the skill content, injected as the task
73
+
74
+ Does not reach it:
75
+ - the CLAUDE.md hierarchy: 4 instruction line(s), 3 of them prohibitions, and the git status snapshot
76
+ - the parent conversation history and the files already read
77
+ - skills invoked in the parent session, unless named in the skills field
78
+ - the output style and the parent's auto memory
79
+
80
+ Tools: inherits every tool available to subagents.
81
+ Runs in the background (the default); a background subagent keeps only a fixed set of built-in tools, 19 of them, plus every MCP tool.
82
+ ```
83
+
84
+ Add `--json` to any command for machine-readable output.
85
+
86
+ ## Checks
87
+
88
+ | ID | What it catches |
89
+ | --- | --- |
90
+ | `not-loaded` | agent file Claude Code skips: unparsable frontmatter, no `name`, a `name` with a colon or leading hyphen, or a `name` with no `description` |
91
+ | `unknown-field` | frontmatter key that is not a subagent field, such as a skill's `allowed-tools`, so it is ignored |
92
+ | `tools-removed` | tool removed from every subagent even when listed, such as `AskUserQuestion` or `ExitPlanMode` outside plan mode |
93
+ | `tools-background-removed` | built-in tool a background subagent does not keep, dropped without an error |
94
+ | `tools-zero` | no entry in `tools` survives the filters, so the agent fails to launch |
95
+ | `tools-denied-conflict` | tool in both `tools` and `disallowedTools`, so it is denied |
96
+ | `skill-missing` | `skills` names a skill that is not in the repository |
97
+ | `skill-not-preloadable` | `skills` names a skill with `disable-model-invocation: true`, which cannot be preloaded |
98
+ | `skill-unreachable` | prompt names a skill that is neither preloaded nor reachable, because the agent has no `Skill` tool |
99
+ | `skill-not-preloaded` | prompt names a skill the agent must discover itself instead of starting with its content |
100
+ | `fork-agent-unresolved` | `agent:` in a forking skill that resolves to nothing, so the fork runs general-purpose with a wider tool pool |
101
+ | `fork-skips-memory` | fork into `Explore` or `Plan`, which skip the `CLAUDE.md` hierarchy and git status |
102
+ | `fork-background-tools` | tool pre-approved in `allowed-tools` that a background fork does not have |
103
+ | `model-unknown` | `model` that is neither an alias nor a full model ID |
104
+
105
+ Severity is about consequence, not style. An error means the definition cannot do what it
106
+ says: the agent does not load, does not launch, or loses a capability it names. A warning
107
+ means it silently gets less than the file promises. A note is behaviour worth knowing that is
108
+ not a mistake.
109
+
110
+ The documented sentences each check is built on are collected in
111
+ [docs/semantics.md](docs/semantics.md), with the date they were read.
112
+
113
+ ## Scope
114
+
115
+ Claude Code only, and only what a repository can carry: `.claude/agents/`, plugin `agents/`
116
+ directories, `.claude/skills/*/SKILL.md`, the `CLAUDE.md` hierarchy with its imports, and
117
+ `.claude/rules/`. Subagents installed at user scope in `~/.claude/agents/` are outside a
118
+ repository, so they are outside a repository check. Runtime behaviour is out of scope too:
119
+ this is a static audit of definitions, not a transcript analyser.
120
+
121
+ ## Configuration
122
+
123
+ Optional. Put the flags you would otherwise repeat into `pyproject.toml`:
124
+
125
+ ```toml
126
+ [tool.rulereach-delegate]
127
+ exclude = ["tests/fixtures/**"]
128
+ strict = false
129
+ ```
130
+
131
+ Projects without a `pyproject.toml` can use a `.rulereach-delegate.toml` with the same keys at
132
+ the top level. If both exist, `.rulereach-delegate.toml` wins, and command line flags win over
133
+ both. An unreadable file, an unknown key or a value of the wrong type is reported on stderr
134
+ rather than ignored.
135
+
136
+ ## In CI
137
+
138
+ ```yaml
139
+ - name: rulereach-delegate
140
+ run: uvx rulereach-delegate check
141
+ ```
142
+
143
+ `check` exits 1 when there is at least one error, 0 otherwise. Use `--strict` to fail on
144
+ warnings as well.
145
+
146
+ ## Alternatives
147
+
148
+ - [skilldoctor](https://github.com/studiomeyer-io/skilldoctor), [skillcheck](https://github.com/erphq/skillcheck),
149
+ [claudelint](https://github.com/pdugan20/claudelint) and
150
+ [claude-plugins-validation](https://github.com/Emasoft/claude-plugins-validation) validate
151
+ the shape of skill, `CLAUDE.md` and subagent files: frontmatter schema, referenced paths,
152
+ security patterns. Some of them check a subagent's frontmatter fields as well. They stop at
153
+ the file; this tool continues into what the runtime does to it, which is where the tool
154
+ filters and the startup composition live.
155
+ - [rule-trace](https://github.com/seanleecoder/rule-trace) answers the same question at
156
+ runtime: it asks the agent to disclose which rules it applied, and counts those disclosures
157
+ over time. That needs your rules migrated into its format and a hook wired up. This tool is
158
+ static and needs nothing but the repository.
159
+ - `claude plugin validate` finds agent files whose frontmatter does not parse. It does not
160
+ flag a file that parses but has no `name`, and it does not model the tool filters.
161
+
162
+ ## Related
163
+
164
+ - [rulereach](https://github.com/Topicspot/rulereach) - whether an instruction file reaches
165
+ the main agent at all: Codex, Claude Code, Cursor, Copilot.
166
+ - [skillfrisk](https://github.com/Topicspot/skillfrisk) - scan agent skills and MCP servers
167
+ for prompt injection and unsafe instructions.
168
+ - [ciparity](https://github.com/Topicspot/ciparity) - find drift between pre-commit hooks
169
+ and your CI pipeline.
170
+
171
+ ## License
172
+
173
+ MIT
Binary file