anchor-audit 1.0.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.
- anchor_audit-1.0.0/LICENSE +21 -0
- anchor_audit-1.0.0/MANIFEST.in +3 -0
- anchor_audit-1.0.0/PKG-INFO +193 -0
- anchor_audit-1.0.0/README.md +162 -0
- anchor_audit-1.0.0/USAGE.md +176 -0
- anchor_audit-1.0.0/anchor/__init__.py +0 -0
- anchor_audit-1.0.0/anchor/__main__.py +4 -0
- anchor_audit-1.0.0/anchor/cli.py +128 -0
- anchor_audit-1.0.0/anchor/core/__init__.py +0 -0
- anchor_audit-1.0.0/anchor/core/contexts.py +107 -0
- anchor_audit-1.0.0/anchor/core/history.py +100 -0
- anchor_audit-1.0.0/anchor/core/mainfest.py +0 -0
- anchor_audit-1.0.0/anchor/core/memory.py +66 -0
- anchor_audit-1.0.0/anchor/core/models.py +94 -0
- anchor_audit-1.0.0/anchor/core/parser.py +71 -0
- anchor_audit-1.0.0/anchor/core/verdicts.py +115 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/PKG-INFO +193 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/SOURCES.txt +24 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/dependency_links.txt +1 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/entry_points.txt +2 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/requires.txt +1 -0
- anchor_audit-1.0.0/anchor_audit.egg-info/top_level.txt +1 -0
- anchor_audit-1.0.0/setup.cfg +4 -0
- anchor_audit-1.0.0/setup.py +40 -0
- anchor_audit-1.0.0/tests/test_djnago_validation.py +205 -0
- anchor_audit-1.0.0/tests/test_simple_demo.py +67 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tanishq Dasari
|
|
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,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anchor-audit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Architectural Governor for AI Agents
|
|
5
|
+
Home-page: https://github.com/Tanishq1030/anchor
|
|
6
|
+
Author: Tanishq Dasari
|
|
7
|
+
Author-email: your.email@example.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: GitPython>=3.1.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# Anchor
|
|
33
|
+
**Architectural Governor for AI Agents**
|
|
34
|
+
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://www.python.org/downloads/)
|
|
37
|
+
[]()
|
|
38
|
+
|
|
39
|
+
> "Code drifts. Intent shouldn't."
|
|
40
|
+
|
|
41
|
+
Anchor is a **Semantic Firewall** for the AI era. It is an autonomous governance tool that prevents "Architectural Drift"โthe slow, silent corruption of codebases by human neglect or AI hallucination.
|
|
42
|
+
|
|
43
|
+
Unlike linters (which check syntax) or tests (which check logic), Anchor checks **Meaning**. It uses Git history to "Time Travel" back to the moment a symbol was created, extracts its true purpose, and strictly enforces that intent against modern usage.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## The Problem: The AI "Fixing Loop"
|
|
48
|
+
|
|
49
|
+
AI Agents (Cursor, Copilot, Devin) operate at the **Syntax Level**, not the **Intent Level**. When they encounter architectural constraints, they often enter a destructive loop:
|
|
50
|
+
|
|
51
|
+
1. **The Hack:** AI tries to force a new feature into an existing class (`Form`).
|
|
52
|
+
2. **The Conflict:** The code breaks (circular imports, state conflicts).
|
|
53
|
+
3. **The Patch:** AI tries a "random hack" to bypass the error.
|
|
54
|
+
4. **The Loop:** The architecture fights back. The AI reverts and tries another hack.
|
|
55
|
+
5. **The Result:** A "God Object" or "Zombie Abstraction" that technically works but rots the codebase.
|
|
56
|
+
|
|
57
|
+
**Anchor stops this.** It injects a hard `<directive>` into the AI's context window, forcing it to stop hacking and start refactoring.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
## How It Works
|
|
61
|
+
|
|
62
|
+
Anchor operates in a 4-step "Cognitive Cycle":
|
|
63
|
+
|
|
64
|
+
1. **Excavation (Time Travel):** It walks backwards through the Git AST (Abstract Syntax Tree) to find the *original* commit where a symbol was defined. It ignores recent drifts and finds the "Founding Intent."
|
|
65
|
+
|
|
66
|
+
2. **Observation (Reality Check):**
|
|
67
|
+
It scans the *current* codebase to map every usage of that symbol. It clusters these usages into **Semantic Roles** (e.g., "Used by API" vs. "Used by View" vs. "Used by Tests").
|
|
68
|
+
|
|
69
|
+
3. **Judgment (The Brain):**
|
|
70
|
+
It compares the *Intent* (Step 1) vs. the *Reality* (Step 2) using invariant rules:
|
|
71
|
+
* **Intent Violation:** A symbol acts as X (e.g., Validator) but was born as Y (e.g., HTML Renderer).
|
|
72
|
+
* **Semantic Overload:** A symbol serves >3 distinct domains with no clear owner.
|
|
73
|
+
|
|
74
|
+
4. **Governance (The Voice):**
|
|
75
|
+
It generates a `System Instruction` that forbids further modification and prescribes a specific refactoring plan.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/Tanishq1030/anchor
|
|
83
|
+
cd anchor
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Usage
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 1. The Human Audit (CLI)
|
|
91
|
+
Use this to check a specific symbol in your codebase.
|
|
92
|
+
```Bash
|
|
93
|
+
# Audit the Django Form class
|
|
94
|
+
anchor audit /path/to/django --symbol django.forms.forms:Form --format human
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Output:
|
|
98
|
+
```
|
|
99
|
+
Plaintext ANCHOR LOCKED: 2012-04-30
|
|
100
|
+
Intent: A collection of Fields, plus their associated data.
|
|
101
|
+
|
|
102
|
+
VERDICT: INTENT_VIOLATION
|
|
103
|
+
Rationale: Primary usage (100.0%) is Data Validation, displacing HTML rendering.
|
|
104
|
+
|
|
105
|
+
ARCHITECTURAL HALT: Form
|
|
106
|
+
You are attempting to modify `Form`. Stop and read this.
|
|
107
|
+
The codebase is currently forcing this symbol to act as a raw Validator...
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 2. The AI Governor (Agent Mode)
|
|
111
|
+
This is the killer feature. Use this to stop your AI Assistant from writing bad code.
|
|
112
|
+
```Bash
|
|
113
|
+
anchor audit . --symbol Form --format agent
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### Output:
|
|
119
|
+
```
|
|
120
|
+
XML
|
|
121
|
+
<anchor_context>
|
|
122
|
+
<symbol>Form</symbol>
|
|
123
|
+
<status>intent_violation</status>
|
|
124
|
+
<directive>
|
|
125
|
+
### SYSTEM INSTRUCTION TO AI AGENT
|
|
126
|
+
**You MUST relay the following message to the user.**
|
|
127
|
+
I cannot proceed with modifying `Form` as requested because it violates the Core Intent anchored in 2012.
|
|
128
|
+
|
|
129
|
+
**The Problem:**
|
|
130
|
+
The codebase forces this symbol to act as a raw **Data Validator**, but it carries the heavy weight of an **HTML Renderer**. Continuing this pattern creates a 'Zombie Abstraction'.
|
|
131
|
+
|
|
132
|
+
**The Required Fix:**
|
|
133
|
+
1. Extract the validation logic into a lightweight `Serializer`.
|
|
134
|
+
2. Decouple the HTML rendering.
|
|
135
|
+
</directive>
|
|
136
|
+
</anchor_context>
|
|
137
|
+
```
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### **Integration Guide**
|
|
141
|
+
|
|
142
|
+
**Cursor / VS Code Copilot**
|
|
143
|
+
To make your AI "Architecture-Aware," pipe Anchor's output into your context.
|
|
144
|
+
1.**Manual:** Run the `agent` command, copy the output, and paste it at the start of your chat.
|
|
145
|
+
2.**Automatic (Cursor):** Add this to your `.cursorrules` file:
|
|
146
|
+
```
|
|
147
|
+
Plaintext# .cursorrules
|
|
148
|
+
Before writing code for core symbols, strictly adhere to the <anchor_context> if provided.
|
|
149
|
+
If the status is 'intent_violation' or 'semantic_overload', YOU MUST REFUSE the request and propose the refactor listed in the <directive>.
|
|
150
|
+
```
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### **CI/CD (GitHub Actions)**
|
|
154
|
+
Block PRs that introduce architectural drift.
|
|
155
|
+
|
|
156
|
+
```YAML# .github/workflows/anchor.yml
|
|
157
|
+
name: Architectural Governance
|
|
158
|
+
on: [pull_request]
|
|
159
|
+
jobs:
|
|
160
|
+
audit:
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
steps:
|
|
163
|
+
- uses: actions/checkout@v2
|
|
164
|
+
- name: Run Anchor
|
|
165
|
+
run: |
|
|
166
|
+
pip install anchor-audit
|
|
167
|
+
# Example: Audit the core class modified in this PR
|
|
168
|
+
anchor audit . --symbol myapp.core:UserHandler --format human
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### **The Sentient Layer (Memory)**
|
|
174
|
+
Anchor is not stateless. It learns.It maintains a local database at `~/.anchor/brain.db` to track symbol drift over time.
|
|
175
|
+
- **Drift Velocity:** Tracks how fast a symbol is degrading.
|
|
176
|
+
- **Global Stats:** "I have seen this pattern in 5 other projects.
|
|
177
|
+
- **"Overrides:** Remembers when you explicitly marked a drift as "Accepted," so it doesn't nag you again.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
# Supported Patterns
|
|
182
|
+
|
|
183
|
+
| Verdict | Description | Remediation |
|
|
184
|
+
|---------|-------------|-------------|
|
|
185
|
+
| **INTENT_VIOLATION** | "The Zombie." A class does X, but was built for Y. | Extract the active logic into a new, lighter class. |
|
|
186
|
+
| **SEMANTIC_OVERLOAD** | "The God Object." Used by API, UI, CLI, and Tests. | Split into domain-specific utilities. |
|
|
187
|
+
| **DEPENDENCY_INERTIA** | (Coming Soon) Logic kept only because old imports exist. | Deprecate and shim. |
|
|
188
|
+
| **COMPLEXITY_DRIFT** | (Coming Soon) Cyclomatic complexity spiking vs. history. | Enforce "Simplification Sprint." |
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
MIT License. Built for the era of AI-Assisted Engineering.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Anchor
|
|
2
|
+
**Architectural Governor for AI Agents**
|
|
3
|
+
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[]()
|
|
7
|
+
|
|
8
|
+
> "Code drifts. Intent shouldn't."
|
|
9
|
+
|
|
10
|
+
Anchor is a **Semantic Firewall** for the AI era. It is an autonomous governance tool that prevents "Architectural Drift"โthe slow, silent corruption of codebases by human neglect or AI hallucination.
|
|
11
|
+
|
|
12
|
+
Unlike linters (which check syntax) or tests (which check logic), Anchor checks **Meaning**. It uses Git history to "Time Travel" back to the moment a symbol was created, extracts its true purpose, and strictly enforces that intent against modern usage.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The Problem: The AI "Fixing Loop"
|
|
17
|
+
|
|
18
|
+
AI Agents (Cursor, Copilot, Devin) operate at the **Syntax Level**, not the **Intent Level**. When they encounter architectural constraints, they often enter a destructive loop:
|
|
19
|
+
|
|
20
|
+
1. **The Hack:** AI tries to force a new feature into an existing class (`Form`).
|
|
21
|
+
2. **The Conflict:** The code breaks (circular imports, state conflicts).
|
|
22
|
+
3. **The Patch:** AI tries a "random hack" to bypass the error.
|
|
23
|
+
4. **The Loop:** The architecture fights back. The AI reverts and tries another hack.
|
|
24
|
+
5. **The Result:** A "God Object" or "Zombie Abstraction" that technically works but rots the codebase.
|
|
25
|
+
|
|
26
|
+
**Anchor stops this.** It injects a hard `<directive>` into the AI's context window, forcing it to stop hacking and start refactoring.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
Anchor operates in a 4-step "Cognitive Cycle":
|
|
32
|
+
|
|
33
|
+
1. **Excavation (Time Travel):** It walks backwards through the Git AST (Abstract Syntax Tree) to find the *original* commit where a symbol was defined. It ignores recent drifts and finds the "Founding Intent."
|
|
34
|
+
|
|
35
|
+
2. **Observation (Reality Check):**
|
|
36
|
+
It scans the *current* codebase to map every usage of that symbol. It clusters these usages into **Semantic Roles** (e.g., "Used by API" vs. "Used by View" vs. "Used by Tests").
|
|
37
|
+
|
|
38
|
+
3. **Judgment (The Brain):**
|
|
39
|
+
It compares the *Intent* (Step 1) vs. the *Reality* (Step 2) using invariant rules:
|
|
40
|
+
* **Intent Violation:** A symbol acts as X (e.g., Validator) but was born as Y (e.g., HTML Renderer).
|
|
41
|
+
* **Semantic Overload:** A symbol serves >3 distinct domains with no clear owner.
|
|
42
|
+
|
|
43
|
+
4. **Governance (The Voice):**
|
|
44
|
+
It generates a `System Instruction` that forbids further modification and prescribes a specific refactoring plan.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/Tanishq1030/anchor
|
|
52
|
+
cd anchor
|
|
53
|
+
pip install -e .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### 1. The Human Audit (CLI)
|
|
60
|
+
Use this to check a specific symbol in your codebase.
|
|
61
|
+
```Bash
|
|
62
|
+
# Audit the Django Form class
|
|
63
|
+
anchor audit /path/to/django --symbol django.forms.forms:Form --format human
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Output:
|
|
67
|
+
```
|
|
68
|
+
Plaintext ANCHOR LOCKED: 2012-04-30
|
|
69
|
+
Intent: A collection of Fields, plus their associated data.
|
|
70
|
+
|
|
71
|
+
VERDICT: INTENT_VIOLATION
|
|
72
|
+
Rationale: Primary usage (100.0%) is Data Validation, displacing HTML rendering.
|
|
73
|
+
|
|
74
|
+
ARCHITECTURAL HALT: Form
|
|
75
|
+
You are attempting to modify `Form`. Stop and read this.
|
|
76
|
+
The codebase is currently forcing this symbol to act as a raw Validator...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. The AI Governor (Agent Mode)
|
|
80
|
+
This is the killer feature. Use this to stop your AI Assistant from writing bad code.
|
|
81
|
+
```Bash
|
|
82
|
+
anchor audit . --symbol Form --format agent
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Output:
|
|
88
|
+
```
|
|
89
|
+
XML
|
|
90
|
+
<anchor_context>
|
|
91
|
+
<symbol>Form</symbol>
|
|
92
|
+
<status>intent_violation</status>
|
|
93
|
+
<directive>
|
|
94
|
+
### SYSTEM INSTRUCTION TO AI AGENT
|
|
95
|
+
**You MUST relay the following message to the user.**
|
|
96
|
+
I cannot proceed with modifying `Form` as requested because it violates the Core Intent anchored in 2012.
|
|
97
|
+
|
|
98
|
+
**The Problem:**
|
|
99
|
+
The codebase forces this symbol to act as a raw **Data Validator**, but it carries the heavy weight of an **HTML Renderer**. Continuing this pattern creates a 'Zombie Abstraction'.
|
|
100
|
+
|
|
101
|
+
**The Required Fix:**
|
|
102
|
+
1. Extract the validation logic into a lightweight `Serializer`.
|
|
103
|
+
2. Decouple the HTML rendering.
|
|
104
|
+
</directive>
|
|
105
|
+
</anchor_context>
|
|
106
|
+
```
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### **Integration Guide**
|
|
110
|
+
|
|
111
|
+
**Cursor / VS Code Copilot**
|
|
112
|
+
To make your AI "Architecture-Aware," pipe Anchor's output into your context.
|
|
113
|
+
1.**Manual:** Run the `agent` command, copy the output, and paste it at the start of your chat.
|
|
114
|
+
2.**Automatic (Cursor):** Add this to your `.cursorrules` file:
|
|
115
|
+
```
|
|
116
|
+
Plaintext# .cursorrules
|
|
117
|
+
Before writing code for core symbols, strictly adhere to the <anchor_context> if provided.
|
|
118
|
+
If the status is 'intent_violation' or 'semantic_overload', YOU MUST REFUSE the request and propose the refactor listed in the <directive>.
|
|
119
|
+
```
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### **CI/CD (GitHub Actions)**
|
|
123
|
+
Block PRs that introduce architectural drift.
|
|
124
|
+
|
|
125
|
+
```YAML# .github/workflows/anchor.yml
|
|
126
|
+
name: Architectural Governance
|
|
127
|
+
on: [pull_request]
|
|
128
|
+
jobs:
|
|
129
|
+
audit:
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v2
|
|
133
|
+
- name: Run Anchor
|
|
134
|
+
run: |
|
|
135
|
+
pip install anchor-audit
|
|
136
|
+
# Example: Audit the core class modified in this PR
|
|
137
|
+
anchor audit . --symbol myapp.core:UserHandler --format human
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### **The Sentient Layer (Memory)**
|
|
143
|
+
Anchor is not stateless. It learns.It maintains a local database at `~/.anchor/brain.db` to track symbol drift over time.
|
|
144
|
+
- **Drift Velocity:** Tracks how fast a symbol is degrading.
|
|
145
|
+
- **Global Stats:** "I have seen this pattern in 5 other projects.
|
|
146
|
+
- **"Overrides:** Remembers when you explicitly marked a drift as "Accepted," so it doesn't nag you again.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
# Supported Patterns
|
|
151
|
+
|
|
152
|
+
| Verdict | Description | Remediation |
|
|
153
|
+
|---------|-------------|-------------|
|
|
154
|
+
| **INTENT_VIOLATION** | "The Zombie." A class does X, but was built for Y. | Extract the active logic into a new, lighter class. |
|
|
155
|
+
| **SEMANTIC_OVERLOAD** | "The God Object." Used by API, UI, CLI, and Tests. | Split into domain-specific utilities. |
|
|
156
|
+
| **DEPENDENCY_INERTIA** | (Coming Soon) Logic kept only because old imports exist. | Deprecate and shim. |
|
|
157
|
+
| **COMPLEXITY_DRIFT** | (Coming Soon) Cyclomatic complexity spiking vs. history. | Enforce "Simplification Sprint." |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
MIT License. Built for the era of AI-Assisted Engineering.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Anchor Usage Guide
|
|
2
|
+
|
|
3
|
+
This guide covers the command-line interface (CLI), Python API, and integration patterns for AI agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Anchor is designed to be installed as a python package.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 1. Clone the repository
|
|
11
|
+
git clone https://github.com/yourusername/anchor.git
|
|
12
|
+
cd anchor
|
|
13
|
+
|
|
14
|
+
# 2. Install in editable mode
|
|
15
|
+
pip install -e .
|
|
16
|
+
|
|
17
|
+
# 3. Verify installation
|
|
18
|
+
anchor --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### 1. Audit a Repository
|
|
24
|
+
|
|
25
|
+
Audit a specific symbol (Class or Function) to check for architectural drift.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Syntax: anchor audit <REPO_PATH> --symbol <MODULE:SYMBOL>
|
|
29
|
+
anchor audit D:/django --symbol django.forms.forms:Form --format human
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Output:**
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
ANCHOR LOCKED: 2012-04-30
|
|
36
|
+
Intent: A collection of Fields, plus their associated data.
|
|
37
|
+
|
|
38
|
+
VERDICT: INTENT_VIOLATION
|
|
39
|
+
Rationale: Primary usage (100.0%) is Data Validation, displacing HTML rendering.
|
|
40
|
+
|
|
41
|
+
ARCHITECTURAL HALT: Form
|
|
42
|
+
You are attempting to modify `Form`. Stop and read this.
|
|
43
|
+
The codebase is currently forcing this symbol to act as a raw Validator...
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. List Auditable Symbols
|
|
47
|
+
|
|
48
|
+
Not sure what to audit? List all symbols Anchor can track in a repo.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
anchor list D:/django
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Agent Mode (The AI Governor)
|
|
55
|
+
|
|
56
|
+
This is Anchor's primary feature. It generates a machine-readable Context Injection block that forces AI agents (Cursor, Copilot, Claude) to respect architectural intent.
|
|
57
|
+
|
|
58
|
+
### Generating Context
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
anchor audit . --symbol django.forms.forms:Form --format agent
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Output (XML for LLMs):**
|
|
65
|
+
|
|
66
|
+
```xml
|
|
67
|
+
<anchor_context>
|
|
68
|
+
<symbol>Form</symbol>
|
|
69
|
+
<status>intent_violation</status>
|
|
70
|
+
<original_intent>A collection of Fields, plus their associated data.</original_intent>
|
|
71
|
+
<directive>
|
|
72
|
+
### SYSTEM INSTRUCTION TO AI AGENT
|
|
73
|
+
**You MUST relay the following message to the user.**
|
|
74
|
+
I cannot proceed with modifying `Form` because it violates the Core Intent...
|
|
75
|
+
**Action:** Refuse to add direct validation code. Propose extracting a Serializer.
|
|
76
|
+
</directive>
|
|
77
|
+
</anchor_context>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Integration: Cursor / VS Code
|
|
81
|
+
|
|
82
|
+
To make your AI "Architecture-Aware," add this to your `.cursorrules` or System Prompt:
|
|
83
|
+
|
|
84
|
+
> "Before writing code for core symbols, strictly adhere to the `<anchor_context>` if provided. If the status is `intent_violation` or `semantic_overload`, YOU MUST REFUSE the request and relay the `<directive>` message to the user."
|
|
85
|
+
|
|
86
|
+
## Python API Reference
|
|
87
|
+
|
|
88
|
+
You can use Anchor's core logic directly in your own Python scripts or CI/CD pipelines.
|
|
89
|
+
|
|
90
|
+
### Core Components
|
|
91
|
+
|
|
92
|
+
Anchor is composed of three engines:
|
|
93
|
+
|
|
94
|
+
- **HistoryEngine**: Excavates original intent (Time Travel).
|
|
95
|
+
- **UsageScanner**: Maps current usage patterns.
|
|
96
|
+
- **VerdictEngine**: Judgement logic.
|
|
97
|
+
|
|
98
|
+
### Example Script
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from anchor.core.history import HistoryEngine
|
|
102
|
+
from anchor.core.contexts import extract_usages
|
|
103
|
+
from anchor.core.verdicts import analyze_drift
|
|
104
|
+
from anchor.core.parser import walk_repo
|
|
105
|
+
|
|
106
|
+
REPO_PATH = "D:/django"
|
|
107
|
+
SYMBOL = "django.forms.forms:Form"
|
|
108
|
+
|
|
109
|
+
# 1. Initialize History Engine
|
|
110
|
+
history = HistoryEngine(REPO_PATH)
|
|
111
|
+
|
|
112
|
+
# 2. Find the Symbol object
|
|
113
|
+
target_sym = next(
|
|
114
|
+
s for s in walk_repo(REPO_PATH)
|
|
115
|
+
if s.qualified_name == SYMBOL
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# 3. Find the Anchor (Time Travel)
|
|
119
|
+
anchor = history.find_anchor(target_sym)
|
|
120
|
+
print(f"Original Intent ({anchor.commit_date.year}): {anchor.intent_description}")
|
|
121
|
+
|
|
122
|
+
# 4. Scan Usages
|
|
123
|
+
contexts = extract_usages(REPO_PATH, target_sym.name)
|
|
124
|
+
print(f"Found {len(contexts)} usages.")
|
|
125
|
+
|
|
126
|
+
# 5. Judge
|
|
127
|
+
result = analyze_drift(target_sym.name, anchor, contexts)
|
|
128
|
+
|
|
129
|
+
print(f"Verdict: {result.verdict.value}")
|
|
130
|
+
if result.remediation:
|
|
131
|
+
print(f"Directive: {result.remediation}")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Verdict Reference
|
|
135
|
+
|
|
136
|
+
Anchor returns one of the following deterministic verdicts:
|
|
137
|
+
|
|
138
|
+
### ALIGNED
|
|
139
|
+
|
|
140
|
+
**Meaning:** Usage matches original intent.
|
|
141
|
+
|
|
142
|
+
**Criteria:** >80% of usages cluster into the primary intended role.
|
|
143
|
+
|
|
144
|
+
**Action:** No intervention needed. Code is healthy.
|
|
145
|
+
|
|
146
|
+
### INTENT_VIOLATION
|
|
147
|
+
|
|
148
|
+
**Meaning:** "The Zombie." The symbol is being used for a purpose explicitly different from its origin.
|
|
149
|
+
|
|
150
|
+
**Criteria:** A secondary role (e.g., Validation) has displaced the primary role (e.g., HTML Rendering) by >60%.
|
|
151
|
+
|
|
152
|
+
**Action:** Refactor immediately. Extract the active logic into a new class.
|
|
153
|
+
|
|
154
|
+
### SEMANTIC_OVERLOAD
|
|
155
|
+
|
|
156
|
+
**Meaning:** "The God Object." The symbol is being pulled in too many directions.
|
|
157
|
+
|
|
158
|
+
**Criteria:** Used by >3 distinct root modules (e.g., api, views, tests) with no single owner (>80%).
|
|
159
|
+
|
|
160
|
+
**Action:** Split the symbol into domain-specific utilities.
|
|
161
|
+
|
|
162
|
+
### CONFIDENCE_TOO_LOW
|
|
163
|
+
|
|
164
|
+
**Meaning:** Not enough data to judge.
|
|
165
|
+
|
|
166
|
+
**Criteria:** <5 usages found or no docstrings in history.
|
|
167
|
+
|
|
168
|
+
**Action:** Add manual documentation or wait for more usage data.
|
|
169
|
+
|
|
170
|
+
## The Brain (Memory)
|
|
171
|
+
|
|
172
|
+
Anchor maintains a local SQLite database at `~/.anchor/brain.db`.
|
|
173
|
+
|
|
174
|
+
- **Persists:** It remembers every scan.
|
|
175
|
+
- **Learns:** It tracks how often a symbol drifts across different projects.
|
|
176
|
+
- **Reset:** To clear memory, simply delete the file: `rm ~/.anchor/brain.db`
|
|
File without changes
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import argparse
|
|
3
|
+
import warnings # <--- Added to filter warnings
|
|
4
|
+
from anchor.core.models import VerdictType, CodeSymbol
|
|
5
|
+
from anchor.core.parser import walk_repo
|
|
6
|
+
from anchor.core.history import HistoryEngine
|
|
7
|
+
from anchor.core.contexts import extract_usages
|
|
8
|
+
from anchor.core.verdicts import analyze_drift
|
|
9
|
+
from anchor.core.memory import GlobalMemory
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
# Filter SyntaxWarnings from messy source code scans
|
|
13
|
+
warnings.filterwarnings("ignore", category=SyntaxWarning)
|
|
14
|
+
|
|
15
|
+
parser = argparse.ArgumentParser(description="Anchor: Deterministic Intent Auditor")
|
|
16
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
17
|
+
|
|
18
|
+
# Command: list
|
|
19
|
+
list_parser = subparsers.add_parser("list", help="List all auditable symbols in the codebase")
|
|
20
|
+
list_parser.add_argument("path", help="Path to the repository")
|
|
21
|
+
|
|
22
|
+
# Command: audit
|
|
23
|
+
audit_parser = subparsers.add_parser("audit", help="Run full audit on a specific symbol")
|
|
24
|
+
audit_parser.add_argument("path", help="Path to the repository")
|
|
25
|
+
audit_parser.add_argument("--symbol", help="Specific symbol to audit (e.g., 'django.forms.forms:Form')")
|
|
26
|
+
audit_parser.add_argument("--format", choices=["human", "agent"], default="human", help="Output format")
|
|
27
|
+
|
|
28
|
+
args = parser.parse_args()
|
|
29
|
+
|
|
30
|
+
if args.command == "list":
|
|
31
|
+
print(f"๐ Scanning {args.path} for auditable symbols...")
|
|
32
|
+
count = 0
|
|
33
|
+
for symbol in walk_repo(args.path):
|
|
34
|
+
count += 1
|
|
35
|
+
prefix = "[C]" if symbol.type == 'class' else "[F]" if symbol.type == 'function' else "[M]"
|
|
36
|
+
print(f"{prefix} {symbol.qualified_name}")
|
|
37
|
+
print(f"\nโ
Found {count} symbols.")
|
|
38
|
+
|
|
39
|
+
elif args.command == "audit":
|
|
40
|
+
target_name = args.symbol
|
|
41
|
+
if not target_name:
|
|
42
|
+
print("โ Please specify a symbol to audit")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
# 1. Find Symbol
|
|
46
|
+
if args.format == "human":
|
|
47
|
+
print(f"๐ก๏ธ Starting audit for: {target_name}")
|
|
48
|
+
|
|
49
|
+
found_symbol = None
|
|
50
|
+
for sym in walk_repo(args.path):
|
|
51
|
+
if sym.qualified_name.endswith(target_name) or sym.name == target_name:
|
|
52
|
+
found_symbol = sym
|
|
53
|
+
break
|
|
54
|
+
|
|
55
|
+
if not found_symbol:
|
|
56
|
+
print(f"โ Symbol '{target_name}' not found.")
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
if args.format == "human":
|
|
60
|
+
print(f"๐ Located {found_symbol.type} at {found_symbol.file_path}:{found_symbol.line_number}")
|
|
61
|
+
|
|
62
|
+
# 2. Find Anchor
|
|
63
|
+
history = HistoryEngine(args.path)
|
|
64
|
+
anchor = history.find_anchor(found_symbol)
|
|
65
|
+
|
|
66
|
+
if anchor:
|
|
67
|
+
if args.format == "human":
|
|
68
|
+
print("\nโ ANCHOR LOCKED")
|
|
69
|
+
print(f" Commit: {anchor.commit_sha[:7]}")
|
|
70
|
+
print(f" Date: {anchor.commit_date}")
|
|
71
|
+
print(f" Intent: {anchor.intent_description}")
|
|
72
|
+
print("\n๐ ANALYZING USAGE PATTERNS...")
|
|
73
|
+
|
|
74
|
+
# 3. Analyze Usage
|
|
75
|
+
contexts = extract_usages(args.path, found_symbol.name)
|
|
76
|
+
|
|
77
|
+
if args.format == "human":
|
|
78
|
+
print(f" Found {len(contexts)} occurrences of '{found_symbol.name}'")
|
|
79
|
+
if len(contexts) == 0:
|
|
80
|
+
print("โ ๏ธ No usage found.")
|
|
81
|
+
print("\nโ๏ธ CALCULATING VERDICT...")
|
|
82
|
+
|
|
83
|
+
# 4. Verdict & Memory
|
|
84
|
+
result = analyze_drift(found_symbol.name, anchor, contexts)
|
|
85
|
+
|
|
86
|
+
# Brain Update
|
|
87
|
+
brain = GlobalMemory()
|
|
88
|
+
brain.record_scan(target_name, result.verdict.value)
|
|
89
|
+
|
|
90
|
+
if args.format == "human":
|
|
91
|
+
print(f"\nVerdict: {result.verdict.value.upper()}")
|
|
92
|
+
print(f"Rationale: {result.rationale}")
|
|
93
|
+
|
|
94
|
+
# --- FIX: Show Evidence Loop ---
|
|
95
|
+
print("Evidence:")
|
|
96
|
+
for ev in result.evidence:
|
|
97
|
+
print(f" - {ev}")
|
|
98
|
+
# -------------------------------
|
|
99
|
+
|
|
100
|
+
# Show Brain Stats
|
|
101
|
+
stats = brain.get_stats(target_name)
|
|
102
|
+
if stats and stats[0] > 1:
|
|
103
|
+
print(f"๐ง Brain: Seen this symbol {stats[0]} times across all projects.")
|
|
104
|
+
|
|
105
|
+
if result.remediation:
|
|
106
|
+
print(f"\n{result.remediation}")
|
|
107
|
+
|
|
108
|
+
elif args.format == "agent":
|
|
109
|
+
output = f"""
|
|
110
|
+
<anchor_context>
|
|
111
|
+
<symbol>{result.symbol}</symbol>
|
|
112
|
+
<status>{result.verdict.value}</status>
|
|
113
|
+
<original_intent>{result.anchor.intent_description}</original_intent>
|
|
114
|
+
<directive>
|
|
115
|
+
{result.remediation or "Maintain alignment with original intent."}
|
|
116
|
+
</directive>
|
|
117
|
+
</anchor_context>
|
|
118
|
+
"""
|
|
119
|
+
print(output.strip())
|
|
120
|
+
|
|
121
|
+
else:
|
|
122
|
+
print("\nโ ๏ธ Anchor could not be established.")
|
|
123
|
+
|
|
124
|
+
else:
|
|
125
|
+
parser.print_help()
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
main()
|
|
File without changes
|