agent-code-guard 0.1.0__py3-none-any.whl
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.
- agent_code_guard/__init__.py +1 -0
- agent_code_guard/analysis/__init__.py +13 -0
- agent_code_guard/analysis/adapters.py +608 -0
- agent_code_guard/analysis/errors.py +13 -0
- agent_code_guard/analysis/facts.py +101 -0
- agent_code_guard/analysis/language_specs.py +82 -0
- agent_code_guard/analysis/pipeline.py +37 -0
- agent_code_guard/analysis/provider.py +45 -0
- agent_code_guard/analysis/regions.py +108 -0
- agent_code_guard/code_guard.py +236 -0
- agent_code_guard/config_validation.py +90 -0
- agent_code_guard/file_selection.py +228 -0
- agent_code_guard/guards/__init__.py +1 -0
- agent_code_guard/guards/callable_size.py +79 -0
- agent_code_guard/guards/complexity.py +94 -0
- agent_code_guard/guards/loc.py +235 -0
- agent_code_guard/guards/markdown_document_size.py +66 -0
- agent_code_guard/guards/markdown_section_size.py +66 -0
- agent_code_guard/guards/nesting.py +109 -0
- agent_code_guard/markdown/__init__.py +6 -0
- agent_code_guard/markdown/facts.py +27 -0
- agent_code_guard/markdown/scanner.py +109 -0
- agent_code_guard/path_matching.py +25 -0
- agent_code_guard/reporting.py +11 -0
- agent_code_guard/result_model.py +128 -0
- agent_code_guard/skill_distribution.py +96 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/LICENSE.txt +21 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/SKILL.md +138 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/agents/openai.yaml +8 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/callable-size-policy.md +39 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/complexity-policy.md +39 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/loc-policy.md +40 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/markdown-size-policy.md +16 -0
- agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/nesting-policy.md +37 -0
- agent_code_guard-0.1.0.dist-info/METADATA +206 -0
- agent_code_guard-0.1.0.dist-info/RECORD +40 -0
- agent_code_guard-0.1.0.dist-info/WHEEL +5 -0
- agent_code_guard-0.1.0.dist-info/entry_points.txt +2 -0
- agent_code_guard-0.1.0.dist-info/licenses/LICENSE +21 -0
- agent_code_guard-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Normalized results shared by Code Guard runners and guard modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
STATE_RANK = {"pass": 0, "review": 1, "fail": 2}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class Finding:
|
|
14
|
+
path: str
|
|
15
|
+
state: str
|
|
16
|
+
native_status: str
|
|
17
|
+
counted_loc: int
|
|
18
|
+
warn_at: int
|
|
19
|
+
fail_at: int
|
|
20
|
+
override_index: int | None = None
|
|
21
|
+
reason: str | None = None
|
|
22
|
+
|
|
23
|
+
def to_json(self) -> dict[str, Any]:
|
|
24
|
+
data = asdict(self)
|
|
25
|
+
return {
|
|
26
|
+
"path": data["path"],
|
|
27
|
+
"state": data["state"],
|
|
28
|
+
"nativeStatus": data["native_status"],
|
|
29
|
+
"countedLoc": data["counted_loc"],
|
|
30
|
+
"warnAt": data["warn_at"],
|
|
31
|
+
"failAt": data["fail_at"],
|
|
32
|
+
"overrideIndex": data["override_index"],
|
|
33
|
+
"reason": data["reason"],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class CallableFinding:
|
|
39
|
+
"""Additive result shape proven by analyzer research; unused by LOC."""
|
|
40
|
+
|
|
41
|
+
path: str
|
|
42
|
+
callable: str
|
|
43
|
+
start_line: int
|
|
44
|
+
end_line: int
|
|
45
|
+
measured: int
|
|
46
|
+
state: str
|
|
47
|
+
thresholds: dict[str, int] | None = None
|
|
48
|
+
details: dict[str, Any] | None = None
|
|
49
|
+
embedded_language: str | None = None
|
|
50
|
+
|
|
51
|
+
def to_json(self) -> dict[str, Any]:
|
|
52
|
+
value = {
|
|
53
|
+
"path": self.path,
|
|
54
|
+
"callable": self.callable,
|
|
55
|
+
"range": {"startLine": self.start_line, "endLine": self.end_line},
|
|
56
|
+
"measured": self.measured,
|
|
57
|
+
"state": self.state,
|
|
58
|
+
"thresholds": self.thresholds,
|
|
59
|
+
}
|
|
60
|
+
if self.details is not None:
|
|
61
|
+
value["details"] = self.details
|
|
62
|
+
if self.embedded_language is not None:
|
|
63
|
+
value["embeddedLanguage"] = self.embedded_language
|
|
64
|
+
return value
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True)
|
|
68
|
+
class MarkdownDocumentFinding:
|
|
69
|
+
path: str
|
|
70
|
+
measured: int
|
|
71
|
+
state: str
|
|
72
|
+
thresholds: dict[str, int]
|
|
73
|
+
|
|
74
|
+
def to_json(self) -> dict[str, Any]:
|
|
75
|
+
return {
|
|
76
|
+
"path": self.path,
|
|
77
|
+
"measured": self.measured,
|
|
78
|
+
"state": self.state,
|
|
79
|
+
"thresholds": self.thresholds,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(frozen=True)
|
|
84
|
+
class MarkdownSectionFinding:
|
|
85
|
+
path: str
|
|
86
|
+
heading: str
|
|
87
|
+
level: int
|
|
88
|
+
start_line: int
|
|
89
|
+
end_line: int
|
|
90
|
+
measured: int
|
|
91
|
+
state: str
|
|
92
|
+
thresholds: dict[str, int]
|
|
93
|
+
|
|
94
|
+
def to_json(self) -> dict[str, Any]:
|
|
95
|
+
return {
|
|
96
|
+
"path": self.path,
|
|
97
|
+
"heading": self.heading,
|
|
98
|
+
"level": self.level,
|
|
99
|
+
"range": {"startLine": self.start_line, "endLine": self.end_line},
|
|
100
|
+
"measured": self.measured,
|
|
101
|
+
"state": self.state,
|
|
102
|
+
"thresholds": self.thresholds,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass(frozen=True)
|
|
107
|
+
class GuardResult:
|
|
108
|
+
guard_id: str
|
|
109
|
+
state: str
|
|
110
|
+
findings: list[Finding | CallableFinding | MarkdownDocumentFinding | MarkdownSectionFinding]
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def required_policies(self) -> list[str]:
|
|
114
|
+
return [self.guard_id] if self.state in {"review", "fail"} else []
|
|
115
|
+
|
|
116
|
+
def to_json(self) -> dict[str, Any]:
|
|
117
|
+
return {
|
|
118
|
+
"state": self.state,
|
|
119
|
+
"findings": [finding.to_json() for finding in self.findings],
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def aggregate_state(results: list[GuardResult]) -> str:
|
|
124
|
+
return max((result.state for result in results), key=STATE_RANK.get, default="pass")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def required_policies(results: list[GuardResult]) -> list[str]:
|
|
128
|
+
return sorted({policy for result in results for policy in result.required_policies})
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Locate and export the version-coupled Code Guard skill payload."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import distribution, version
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import shutil
|
|
9
|
+
from urllib.parse import unquote, urlparse
|
|
10
|
+
from urllib.request import url2pathname
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
PAYLOAD_FILES = (
|
|
14
|
+
"SKILL.md",
|
|
15
|
+
"LICENSE.txt",
|
|
16
|
+
"agents/openai.yaml",
|
|
17
|
+
"references/callable-size-policy.md",
|
|
18
|
+
"references/complexity-policy.md",
|
|
19
|
+
"references/loc-policy.md",
|
|
20
|
+
"references/markdown-size-policy.md",
|
|
21
|
+
"references/nesting-policy.md",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def skill_path() -> Path:
|
|
26
|
+
"""Return the installed canonical skill payload directory."""
|
|
27
|
+
package = distribution("agent-code-guard")
|
|
28
|
+
suffix = "share/agent-code-guard/skill/SKILL.md"
|
|
29
|
+
path = next(
|
|
30
|
+
(
|
|
31
|
+
Path(package.locate_file(item)).parent
|
|
32
|
+
for item in package.files or ()
|
|
33
|
+
if str(item).replace("\\", "/").endswith(suffix)
|
|
34
|
+
),
|
|
35
|
+
None,
|
|
36
|
+
)
|
|
37
|
+
if path is None:
|
|
38
|
+
path = _editable_skill_path(package)
|
|
39
|
+
if path is None:
|
|
40
|
+
raise ValueError("installed distribution does not contain the Code Guard skill payload")
|
|
41
|
+
_validate_payload(path)
|
|
42
|
+
return path.resolve()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def export_skill(target: Path) -> Path:
|
|
46
|
+
"""Copy the installed payload into an empty caller-owned directory."""
|
|
47
|
+
target = target.expanduser().resolve()
|
|
48
|
+
if target.exists():
|
|
49
|
+
if not target.is_dir():
|
|
50
|
+
raise ValueError(f"skill export target is not a directory: {target}")
|
|
51
|
+
if any(target.iterdir()):
|
|
52
|
+
raise ValueError(f"skill export target is not empty: {target}")
|
|
53
|
+
else:
|
|
54
|
+
target.mkdir(parents=True)
|
|
55
|
+
|
|
56
|
+
source_root = skill_path()
|
|
57
|
+
for relative in PAYLOAD_FILES:
|
|
58
|
+
source = source_root / relative
|
|
59
|
+
if source.is_symlink() or not source.is_file():
|
|
60
|
+
raise ValueError(f"installed skill payload has an unsafe or missing file: {relative}")
|
|
61
|
+
destination = target / relative
|
|
62
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
shutil.copyfile(source, destination)
|
|
64
|
+
(target / ".agent-code-guard-version").write_text(
|
|
65
|
+
f'{version("agent-code-guard")}\n', encoding="utf-8", newline="\n",
|
|
66
|
+
)
|
|
67
|
+
return target
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _validate_payload(path: Path) -> None:
|
|
71
|
+
if path.is_symlink() or not path.is_dir():
|
|
72
|
+
raise ValueError(f"installed skill payload is missing: {path}")
|
|
73
|
+
for relative in PAYLOAD_FILES:
|
|
74
|
+
candidate = path / relative
|
|
75
|
+
relative_path = Path(relative)
|
|
76
|
+
parents = (
|
|
77
|
+
path.joinpath(*relative_path.parts[:index])
|
|
78
|
+
for index in range(1, len(relative_path.parts))
|
|
79
|
+
)
|
|
80
|
+
if any(parent.is_symlink() for parent in parents) or candidate.is_symlink() or not candidate.is_file():
|
|
81
|
+
raise ValueError(f"installed skill payload has an unsafe or missing file: {relative}")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _editable_skill_path(package) -> Path | None:
|
|
85
|
+
"""Use PEP 610 metadata when setuptools omits data-files from editable wheels."""
|
|
86
|
+
direct_url = package.read_text("direct_url.json")
|
|
87
|
+
if direct_url is None:
|
|
88
|
+
return None
|
|
89
|
+
metadata = json.loads(direct_url)
|
|
90
|
+
if not metadata.get("dir_info", {}).get("editable"):
|
|
91
|
+
return None
|
|
92
|
+
parsed = urlparse(metadata.get("url", ""))
|
|
93
|
+
if parsed.scheme != "file":
|
|
94
|
+
return None
|
|
95
|
+
checkout = Path(url2pathname(unquote(parsed.path)))
|
|
96
|
+
return checkout / "skills" / "code-guard"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stef Karyotidis
|
|
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,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-guard
|
|
3
|
+
description: Use when creating, editing, reviewing, or refactoring supported code or Markdown documentation to run deterministic guardrails and load only the policy guidance required by triggered findings.
|
|
4
|
+
license: Complete terms in LICENSE.txt
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Guard
|
|
8
|
+
|
|
9
|
+
Use this skill whenever supported code or Markdown documentation artifacts are created, edited, reviewed, or refactored.
|
|
10
|
+
|
|
11
|
+
Code Guard provides deterministic measurements that act as anchors for agent judgment. The measurement is objective; the response to a `REVIEW` finding still requires design judgment.
|
|
12
|
+
|
|
13
|
+
## Result states
|
|
14
|
+
|
|
15
|
+
- `PASS` — no special action is required.
|
|
16
|
+
- `REVIEW` — inspect the finding and either accept it with a meaningful justification or improve the code when doing so improves real clarity, cohesion, or boundaries.
|
|
17
|
+
- `FAIL` — do not declare normal completion until the condition is fixed or an explicitly permitted/user-approved exception applies.
|
|
18
|
+
|
|
19
|
+
## Universal rules
|
|
20
|
+
|
|
21
|
+
1. Never game a metric.
|
|
22
|
+
2. Preserve readability and the repository's normal formatting/style conventions.
|
|
23
|
+
3. Do not compress independent statements, remove useful structure/comments, obscure control flow, or minify handwritten source to lower a measurement.
|
|
24
|
+
4. Do not create meaningless helpers, artificial files, unnecessary abstractions, or indirection mainly to reduce a metric.
|
|
25
|
+
5. `REVIEW` is not an automatic refactor instruction.
|
|
26
|
+
6. Refactor only when the change improves the code rather than merely improving the score.
|
|
27
|
+
7. Do not create, broaden, or alter policy exceptions/configuration solely to make Code Guard pass without explicit user approval.
|
|
28
|
+
8. Do not expand the current task to unrelated pre-existing debt. Normal development checks changed/current-work files; full-repository audit is separate.
|
|
29
|
+
|
|
30
|
+
## Workflow
|
|
31
|
+
|
|
32
|
+
With Git, run the installed Code Guard command after supported code or Markdown documentation edits:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
code-guard . --changed-only
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
An installed Agent Code Guard distribution provides both the command and this
|
|
39
|
+
version-matched skill payload. The skill's normal execution route is always the
|
|
40
|
+
installed `code-guard` command.
|
|
41
|
+
|
|
42
|
+
For repository development only, the compatibility runner remains available
|
|
43
|
+
directly from a checkout. It is not part of the externally installed skill
|
|
44
|
+
payload or the normal end-user execution route:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python3 skills/code-guard/scripts/code_guard.py . --changed-only
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`pyproject.toml` canonically owns the production pins. Tree-sitter remains
|
|
51
|
+
dormant during LOC-only execution; failure to load a required provider or
|
|
52
|
+
grammar is a deterministic tool error during normal zero-config syntax analysis.
|
|
53
|
+
Disabling every syntax guard preserves the lazy no-Tree-sitter path. A strictly
|
|
54
|
+
LOC-only result also requires both Markdown guards to be explicitly disabled.
|
|
55
|
+
|
|
56
|
+
Without Git or another VCS that can provide changed scope, pass exactly the files you created or modified. You are responsible for supplying the complete edited-file set:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
code-guard src/Foo.py src/Bar.ts docs/guide.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Do not create a manifest or temporary scope file. Specific positional files mean “inspect these artifacts.” A directory or `.` means a deliberate recursive audit when no Git selector is used. Positional files/directories bound the candidates selected by `--changed-only`, `--staged`, or `--base-ref`; Git selection fails outside a Git repository and never falls back to an audit.
|
|
63
|
+
|
|
64
|
+
Recursive directory discovery does not follow symlinks. An explicitly supplied
|
|
65
|
+
file symlink is treated as caller intent; an explicit directory symlink is
|
|
66
|
+
rejected rather than recursively traversed.
|
|
67
|
+
|
|
68
|
+
Prefer normal zero-config scope and respect project `scope.exclude`; do not
|
|
69
|
+
remove or alter exclusions merely to silence findings. Repeated
|
|
70
|
+
`--scope-exclude` is caller-supplied all-guard scope policy and composes with
|
|
71
|
+
project exclusions. LOC `--exclude` remains LOC-specific. Explicit files may
|
|
72
|
+
intentionally inspect Git-ignored or built-in-pruned artifacts, unless Code
|
|
73
|
+
Guard `scope.exclude` or `--scope-exclude` removes them.
|
|
74
|
+
|
|
75
|
+
When all guards return `PASS`, no detailed policy file needs to be loaded.
|
|
76
|
+
|
|
77
|
+
When a guard returns `REVIEW` or `FAIL`, read only the policy file named by that finding. The runner returns required policy identifiers/files in both human-readable and JSON output.
|
|
78
|
+
|
|
79
|
+
Policy references:
|
|
80
|
+
|
|
81
|
+
- file LOC: `references/loc-policy.md`
|
|
82
|
+
- callable size: `references/callable-size-policy.md`
|
|
83
|
+
- nesting depth: `references/nesting-policy.md`
|
|
84
|
+
- cyclomatic complexity: `references/complexity-policy.md`
|
|
85
|
+
- Markdown document/section size: `references/markdown-size-policy.md`
|
|
86
|
+
|
|
87
|
+
Do not load unrelated guard policies merely because they exist.
|
|
88
|
+
|
|
89
|
+
## Scope
|
|
90
|
+
|
|
91
|
+
Code Guard is intentionally limited to deterministic concerns that are broadly applicable across conventional programming languages.
|
|
92
|
+
|
|
93
|
+
Guards:
|
|
94
|
+
|
|
95
|
+
- file LOC (implemented and enabled by default);
|
|
96
|
+
- source/container and syntax facts (production infrastructure, not a guard);
|
|
97
|
+
- callable LOC (implemented and enabled by default; REVIEW greater than 80);
|
|
98
|
+
- structural nesting (implemented and enabled by default; REVIEW greater than 4);
|
|
99
|
+
- cyclomatic complexity (implemented and enabled by default; REVIEW greater than 15).
|
|
100
|
+
- Markdown document physical size (implemented for `.md` and enabled by default; REVIEW greater than 800);
|
|
101
|
+
- Markdown direct-section physical size (implemented for `.md` and enabled by default; REVIEW greater than 200).
|
|
102
|
+
|
|
103
|
+
Callable LOC needs no invented configuration to activate it. Omission or
|
|
104
|
+
`enabled: true` uses 80; an authorized positive-integer `reviewAt` overrides it,
|
|
105
|
+
and `enabled: false` disables it. Exactly the effective threshold passes;
|
|
106
|
+
larger callables review and never fail. Load
|
|
107
|
+
`references/callable-size-policy.md` only when `callableSize` appears in
|
|
108
|
+
`requiredPolicies`.
|
|
109
|
+
|
|
110
|
+
Structural nesting is executable control-flow depth, not visual, markup, brace,
|
|
111
|
+
or indentation depth. Omission or `enabled: true` uses 4; an authorized
|
|
112
|
+
positive-integer `reviewAt` overrides it, and `enabled: false` disables it.
|
|
113
|
+
Exactly the effective depth passes; greater depth reviews and never fails. Load `references/nesting-policy.md` only when `nesting`
|
|
114
|
+
appears in `requiredPolicies`.
|
|
115
|
+
|
|
116
|
+
Cyclomatic complexity is baseline 1 plus normalized decisions owned by the
|
|
117
|
+
callable. Omission or `enabled: true` uses 15; an authorized positive-integer
|
|
118
|
+
`reviewAt` overrides it, and `enabled: false` disables it. Short-circuit
|
|
119
|
+
booleans and fallback/null-aware constructs contribute zero. Lambda boundaries
|
|
120
|
+
are independent. Exactly the effective threshold passes; greater complexity
|
|
121
|
+
reviews and never fails. Load `references/complexity-policy.md` only when
|
|
122
|
+
`complexity` appears in `requiredPolicies`.
|
|
123
|
+
|
|
124
|
+
Markdown document and direct-section size count all physical lines. Sections
|
|
125
|
+
run from a supported heading through the line before the next heading of any
|
|
126
|
+
level, or EOF. Exact effective thresholds pass; greater measurements review and
|
|
127
|
+
never fail. Load `references/markdown-size-policy.md` when either
|
|
128
|
+
`markdownDocumentSize` or `markdownSectionSize` appears in `requiredPolicies`.
|
|
129
|
+
Review navigation and responsibility without mechanically splitting coherent
|
|
130
|
+
specifications or gaming headings/formatting.
|
|
131
|
+
|
|
132
|
+
Do not invent configuration, disable a guard, or raise its threshold
|
|
133
|
+
merely to silence a finding. Respect built-ins and only project/user-authorized overrides.
|
|
134
|
+
REVIEW requires inspection and justification, not mandatory refactoring.
|
|
135
|
+
|
|
136
|
+
Agent Code Guard is the canonical LOC implementation. Agent LOC Guard is the completed prototype/reference whose mature behavior was migrated from commit `75ab39d261dbc65f78815836fac90add16d265d1`.
|
|
137
|
+
|
|
138
|
+
Project-specific architecture rules, framework-specific checks, arbitrary style preferences, security scanners, and dependency auditing are outside the universal core.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Code Guard"
|
|
3
|
+
short_description: "Deterministic code guardrails for agents"
|
|
4
|
+
brand_color: "#2563EB"
|
|
5
|
+
default_prompt: "Use $code-guard to check changed supported code and Markdown documentation, then load only the policies required by triggered findings."
|
|
6
|
+
|
|
7
|
+
policy:
|
|
8
|
+
allow_implicit_invocation: true
|
agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/callable-size-policy.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Callable Size Policy
|
|
2
|
+
|
|
3
|
+
Callable size measures the physical LOC of a function, method, constructor, closure, or equivalent callable unit.
|
|
4
|
+
|
|
5
|
+
This guard exists because a source file can remain modest in size while one operation grows large enough to become difficult to understand or change safely.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
The calibrated universal default is REVIEW above 80 physical LOC. Exactly 80
|
|
10
|
+
passes. Authorized project/user configuration may supply a positive
|
|
11
|
+
`guards.callableSize.reviewAt` override or explicitly disable the guard. The
|
|
12
|
+
guard has no FAIL threshold.
|
|
13
|
+
|
|
14
|
+
## On REVIEW
|
|
15
|
+
|
|
16
|
+
Inspect whether the callable:
|
|
17
|
+
|
|
18
|
+
- performs one coherent operation;
|
|
19
|
+
- mixes separable stages or responsibilities;
|
|
20
|
+
- contains large regions that have meaningful names and independent contracts;
|
|
21
|
+
- has accumulated error handling, branching, transformation, persistence, or orchestration that belongs elsewhere;
|
|
22
|
+
- is long mainly because the operation is legitimately linear and easier to understand in one place.
|
|
23
|
+
|
|
24
|
+
Extract code only when the extracted operation is genuinely cohesive and its name/interface improves comprehension.
|
|
25
|
+
|
|
26
|
+
REVIEW requires inspection, not automatic refactoring. Examine the callable's
|
|
27
|
+
cohesion, responsibility, and growth. Split it only when the resulting design is
|
|
28
|
+
clearer, and preserve the project's conventions.
|
|
29
|
+
|
|
30
|
+
## Anti-gaming
|
|
31
|
+
|
|
32
|
+
Do not create tiny meaningless helper methods merely to reduce callable LOC. Do not move arbitrary chunks of a procedure behind names such as `ProcessPart1`, `HandleStuff`, or equivalent abstractions that add navigation without improving design.
|
|
33
|
+
|
|
34
|
+
Do not compress formatting or combine independent statements onto fewer physical lines to lower the measurement.
|
|
35
|
+
|
|
36
|
+
Do not alter the threshold or disable the guard merely to silence a finding.
|
|
37
|
+
Only respect such a change when the project or user has authorized it.
|
|
38
|
+
|
|
39
|
+
A lower callable LOC number is useful only when the resulting code is at least as readable and maintainable as before.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Cyclomatic Complexity Policy
|
|
2
|
+
|
|
3
|
+
Cyclomatic complexity measures the number of independent control-flow paths through a callable.
|
|
4
|
+
|
|
5
|
+
This guard exists because a callable can be short and only lightly nested while still containing enough branching and decision logic to be difficult to reason about or test safely.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
Complexity is enabled by default. Exactly 15 passes and greater complexity
|
|
10
|
+
reviews. It is REVIEW-only and never fails. An authorized project/user positive
|
|
11
|
+
integer `reviewAt` may override the default, and explicit disablement is allowed.
|
|
12
|
+
Short-circuit booleans deliberately contribute zero. Agents must not weaken or
|
|
13
|
+
disable the guard merely to silence findings.
|
|
14
|
+
|
|
15
|
+
## On REVIEW
|
|
16
|
+
|
|
17
|
+
Inspect whether complexity comes from:
|
|
18
|
+
|
|
19
|
+
- many genuinely independent execution paths;
|
|
20
|
+
- accumulated conditional branching;
|
|
21
|
+
- mixed responsibilities;
|
|
22
|
+
- mode/type/state switches that should perhaps be modeled explicitly;
|
|
23
|
+
- error handling mixed with core behavior;
|
|
24
|
+
- legitimate parsers, protocol handling, state machines, or rule evaluation where branching may be inherent.
|
|
25
|
+
|
|
26
|
+
Consider refactoring only when the resulting structure makes behavior easier to understand, test, or change.
|
|
27
|
+
REVIEW is an inspection request, not an automatic decomposition instruction.
|
|
28
|
+
|
|
29
|
+
## Anti-gaming
|
|
30
|
+
|
|
31
|
+
Do not lower complexity by hiding decisions behind meaningless wrappers, opaque boolean expressions, lookup tricks, exception flow, or abstractions whose main purpose is changing the score.
|
|
32
|
+
|
|
33
|
+
Do not split one coherent decision process into scattered helpers when that makes the execution model harder to follow.
|
|
34
|
+
|
|
35
|
+
Do not convert clear branches into clever expressions or split coherent parsers,
|
|
36
|
+
state machines, and protocol handlers merely to lower the number. Preserve
|
|
37
|
+
project and language idioms.
|
|
38
|
+
|
|
39
|
+
A lower complexity score is not an improvement unless the resulting behavior and structure are clearer.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# File LOC Policy
|
|
2
|
+
|
|
3
|
+
This is the canonical Agent Code Guard policy for oversized handwritten source files. LOC is a deterministic review signal, not proof that every large file has poor architecture.
|
|
4
|
+
|
|
5
|
+
## Core rule
|
|
6
|
+
|
|
7
|
+
- Up to 400 counted LOC: `PASS`.
|
|
8
|
+
- 401 through 600 counted LOC: `REVIEW`.
|
|
9
|
+
- More than 600 counted LOC: `FAIL` by default unless an explicit approved exemption applies.
|
|
10
|
+
- An existing applicable exemption is `PASS` with native `exempt` status and its reason retained.
|
|
11
|
+
|
|
12
|
+
Counting and selection follow the canonical runner. By default, LOC is non-blank physical lines and comments count. Normal development uses `--changed-only`: staged, unstaged, and untracked current work relative to `HEAD`. A scan without a selection flag is an explicit full-repository audit.
|
|
13
|
+
|
|
14
|
+
## REVIEW interpretation
|
|
15
|
+
|
|
16
|
+
Inspect whether the file remains cohesive and single-responsibility, whether its size is necessary orchestration or linear structure, whether separable responsibilities are mixed, and whether expected near-term growth changes that judgment.
|
|
17
|
+
|
|
18
|
+
`REVIEW` does not automatically require refactoring. Split only when doing so improves real responsibility boundaries or clarity; accept the warning when the file remains cohesive and a split would add harmful indirection.
|
|
19
|
+
|
|
20
|
+
Report either `warning accepted with justification: ...` or `split performed because: ...`.
|
|
21
|
+
|
|
22
|
+
## FAIL and exemptions
|
|
23
|
+
|
|
24
|
+
For `FAIL`, refactor below the hard cap when that improves the design or obtain explicit user approval for a justified exemption. Otherwise report `hard cap reached; user approval required`.
|
|
25
|
+
|
|
26
|
+
Existing `allowedLargeFiles` entries may be honored with their configured reasons. Agents must not create, broaden, modify, repurpose, or invent exemptions merely to pass. Threshold overrides are also explicit policy decisions; agents must not create, broaden, or relax them merely to bypass a finding without explicit approval or existing project policy.
|
|
27
|
+
|
|
28
|
+
Do not infer approval from inconvenience, historical size, a nearby exemption, time pressure, or a request to finish the coding task.
|
|
29
|
+
|
|
30
|
+
## Do not game LOC
|
|
31
|
+
|
|
32
|
+
Project formatting conventions take priority. Never combine independent statements, compress control flow or expressions unusually, minify handwritten code, remove useful comments/structure, or fight the formatter merely to lower physical LOC.
|
|
33
|
+
|
|
34
|
+
Legitimate reductions improve the code: remove redundancy or dead code, simplify control flow, consolidate duplication when appropriate, or split cohesive responsibilities. Prefer cohesive modules over artificial fragmentation.
|
|
35
|
+
|
|
36
|
+
## Scope discipline
|
|
37
|
+
|
|
38
|
+
Changed code is evaluated in its resulting form, including a legacy file modified by the task. Unrelated legacy debt belongs to explicit audit work and must not expand a normal change unnecessarily.
|
|
39
|
+
|
|
40
|
+
Test files may exceed the review threshold when clearly grouped and navigable. They still require explicit approval above the hard cap.
|
agent_code_guard-0.1.0.data/data/share/agent-code-guard/skill/references/markdown-size-policy.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Markdown Size Review Policy
|
|
2
|
+
|
|
3
|
+
Use this policy when `markdownDocumentSize` or `markdownSectionSize` appears in
|
|
4
|
+
`requiredPolicies`.
|
|
5
|
+
|
|
6
|
+
A Markdown size REVIEW is an instruction to inspect navigation and
|
|
7
|
+
responsibility, not an automatic instruction to split the document or section.
|
|
8
|
+
`reviewed; coherent; keep` is a valid outcome for cohesive specifications,
|
|
9
|
+
reference material, tables, procedures, and code-heavy sections.
|
|
10
|
+
|
|
11
|
+
Improve navigation or responsibility boundaries only when the result is
|
|
12
|
+
genuinely clearer. Do not add meaningless headings to lower section size,
|
|
13
|
+
mechanically split coherent material, compress formatting or remove useful
|
|
14
|
+
blank lines, or hide content in fenced code. Agents must not raise thresholds or
|
|
15
|
+
disable either guard merely to silence a finding; project or user authority is
|
|
16
|
+
required for configuration changes.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Nesting Depth Policy
|
|
2
|
+
|
|
3
|
+
Nesting depth measures how deeply control-flow structures are nested within a callable.
|
|
4
|
+
|
|
5
|
+
This guard exists because deeply nested code can be difficult to reason about even when the file and callable are not especially long.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
The calibrated universal default is REVIEW above structural depth 4. Exactly 4
|
|
10
|
+
passes. Authorized project/user configuration may supply a positive
|
|
11
|
+
`guards.nesting.reviewAt` override or explicitly disable the guard. The guard
|
|
12
|
+
has no FAIL threshold.
|
|
13
|
+
|
|
14
|
+
## On REVIEW
|
|
15
|
+
|
|
16
|
+
Inspect whether the nesting reflects:
|
|
17
|
+
|
|
18
|
+
- avoidable conditional pyramids;
|
|
19
|
+
- loops nested inside branches with additional branching;
|
|
20
|
+
- validation/error paths that could be expressed more clearly with guard clauses or early exits;
|
|
21
|
+
- multiple responsibilities entangled in one callable;
|
|
22
|
+
- state-machine, parser, traversal, or other logic where deeper nesting may be inherent and still readable.
|
|
23
|
+
|
|
24
|
+
REVIEW means inspect control-flow readability; it is not an automatic refactor.
|
|
25
|
+
Consider guard clauses or extraction only when they improve clarity. Preserve
|
|
26
|
+
idiomatic language and project structure.
|
|
27
|
+
|
|
28
|
+
## Anti-gaming
|
|
29
|
+
|
|
30
|
+
Do not flatten code merely to reduce the measured depth if the result becomes harder to follow.
|
|
31
|
+
|
|
32
|
+
Do not hide nested decisions behind meaningless helper calls or obscure boolean expressions. Do not replace clear structured control flow with clever expressions, compressed conditionals, exception tricks, or other forms whose primary purpose is lowering the metric.
|
|
33
|
+
|
|
34
|
+
Do not change or disable the configured threshold merely to silence a finding.
|
|
35
|
+
Only respect such a change when the project or user has authorized it.
|
|
36
|
+
|
|
37
|
+
The preferred outcome is clearer control flow, not a smaller number at any cost.
|