aigis-lint 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. aigis_lint-0.2.0/.aigis.yaml +8 -0
  2. aigis_lint-0.2.0/.github/workflows/aigis.yml +30 -0
  3. aigis_lint-0.2.0/.gitignore +23 -0
  4. aigis_lint-0.2.0/26.0.1 +0 -0
  5. aigis_lint-0.2.0/LICENSE +21 -0
  6. aigis_lint-0.2.0/PKG-INFO +350 -0
  7. aigis_lint-0.2.0/README.md +329 -0
  8. aigis_lint-0.2.0/docs/RELEASE_NOTES_v0.2.0.md +88 -0
  9. aigis_lint-0.2.0/docs/aeg003_post_ag2_validation.md +41 -0
  10. aigis_lint-0.2.0/docs/favicon.png +0 -0
  11. aigis_lint-0.2.0/docs/framework_scorecard.md +75 -0
  12. aigis_lint-0.2.0/docs/issues_seed.md +87 -0
  13. aigis_lint-0.2.0/docs/launch_checklist.md +48 -0
  14. aigis_lint-0.2.0/docs/logo-200.png +0 -0
  15. aigis_lint-0.2.0/docs/logo-64.png +0 -0
  16. aigis_lint-0.2.0/docs/logo.png +0 -0
  17. aigis_lint-0.2.0/docs/media_plan.md +97 -0
  18. aigis_lint-0.2.0/docs/release_readiness.md +73 -0
  19. aigis_lint-0.2.0/docs/repo_positioning.md +44 -0
  20. aigis_lint-0.2.0/docs/roadmap.md +41 -0
  21. aigis_lint-0.2.0/docs/roadmap_issues.md +139 -0
  22. aigis_lint-0.2.0/examples/.aigis.yaml +23 -0
  23. aigis_lint-0.2.0/examples/safe_agent.py +32 -0
  24. aigis_lint-0.2.0/examples/unbounded_agent.py +27 -0
  25. aigis_lint-0.2.0/examples/unbounded_retry.py +17 -0
  26. aigis_lint-0.2.0/examples/unsafe_tool.py +20 -0
  27. aigis_lint-0.2.0/pyproject.toml +39 -0
  28. aigis_lint-0.2.0/python +0 -0
  29. aigis_lint-0.2.0/src/aigis/__init__.py +3 -0
  30. aigis_lint-0.2.0/src/aigis/analyzer.py +982 -0
  31. aigis_lint-0.2.0/src/aigis/baseline.py +67 -0
  32. aigis_lint-0.2.0/src/aigis/cli.py +164 -0
  33. aigis_lint-0.2.0/src/aigis/config.py +45 -0
  34. aigis_lint-0.2.0/src/aigis/frameworks/__init__.py +63 -0
  35. aigis_lint-0.2.0/src/aigis/frameworks/autogen.py +45 -0
  36. aigis_lint-0.2.0/src/aigis/frameworks/crewai.py +21 -0
  37. aigis_lint-0.2.0/src/aigis/frameworks/custom.py +17 -0
  38. aigis_lint-0.2.0/src/aigis/frameworks/langchain.py +7 -0
  39. aigis_lint-0.2.0/src/aigis/frameworks/langgraph.py +26 -0
  40. aigis_lint-0.2.0/src/aigis/frameworks/openai_agents.py +35 -0
  41. aigis_lint-0.2.0/src/aigis/graph.py +36 -0
  42. aigis_lint-0.2.0/src/aigis/models.py +110 -0
  43. aigis_lint-0.2.0/src/aigis/output.py +238 -0
  44. aigis_lint-0.2.0/src/aigis/output_html.py +495 -0
  45. aigis_lint-0.2.0/src/aigis/rules/__init__.py +25 -0
  46. aigis_lint-0.2.0/src/aigis/rules/aigis001_unguarded_mutating.py +68 -0
  47. aigis_lint-0.2.0/src/aigis/rules/aigis002_privileged_no_consent.py +81 -0
  48. aigis_lint-0.2.0/src/aigis/rules/aigis003_missing_budget.py +76 -0
  49. aigis_lint-0.2.0/src/aigis/rules/aigis004_unbounded_retry.py +149 -0
  50. aigis_lint-0.2.0/src/aigis/rules/aigis005_user_controlled_budget.py +124 -0
  51. aigis_lint-0.2.0/src/aigis/rules/aigis006_raw_history_retrieval.py +130 -0
  52. aigis_lint-0.2.0/src/aigis/suppression.py +87 -0
  53. aigis_lint-0.2.0/tests/__init__.py +0 -0
  54. aigis_lint-0.2.0/tests/conftest.py +11 -0
  55. aigis_lint-0.2.0/tests/fixtures/autogen_exec_budget.py +24 -0
  56. aigis_lint-0.2.0/tests/fixtures/autogen_groupchat_manager_propagation.py +17 -0
  57. aigis_lint-0.2.0/tests/fixtures/autogen_initiate_group_chat_safe.py +16 -0
  58. aigis_lint-0.2.0/tests/fixtures/autogen_initiate_group_chat_unsafe.py +14 -0
  59. aigis_lint-0.2.0/tests/fixtures/autogen_no_exec_budget.py +16 -0
  60. aigis_lint-0.2.0/tests/fixtures/autogen_safe.py +18 -0
  61. aigis_lint-0.2.0/tests/fixtures/autogen_unsafe.py +22 -0
  62. aigis_lint-0.2.0/tests/fixtures/crewai_safe.py +28 -0
  63. aigis_lint-0.2.0/tests/fixtures/crewai_unsafe.py +31 -0
  64. aigis_lint-0.2.0/tests/fixtures/custom_approval.py +54 -0
  65. aigis_lint-0.2.0/tests/fixtures/exec_budget_wrong_var.py +12 -0
  66. aigis_lint-0.2.0/tests/fixtures/false_positive_edge.py +30 -0
  67. aigis_lint-0.2.0/tests/fixtures/inline_suppression.py +23 -0
  68. aigis_lint-0.2.0/tests/fixtures/langgraph_config_var_budget.py +19 -0
  69. aigis_lint-0.2.0/tests/fixtures/langgraph_exec_budget.py +18 -0
  70. aigis_lint-0.2.0/tests/fixtures/langgraph_interrupt_false_positive.py +25 -0
  71. aigis_lint-0.2.0/tests/fixtures/langgraph_interrupt_safe.py +26 -0
  72. aigis_lint-0.2.0/tests/fixtures/langgraph_safe_patterns.py +34 -0
  73. aigis_lint-0.2.0/tests/fixtures/misleading_names.py +21 -0
  74. aigis_lint-0.2.0/tests/fixtures/nested_wrappers.py +47 -0
  75. aigis_lint-0.2.0/tests/fixtures/openai_agents_alias_budget.py +14 -0
  76. aigis_lint-0.2.0/tests/fixtures/openai_agents_exec_budget.py +22 -0
  77. aigis_lint-0.2.0/tests/fixtures/openai_agents_no_exec_budget.py +22 -0
  78. aigis_lint-0.2.0/tests/fixtures/openai_agents_safe.py +34 -0
  79. aigis_lint-0.2.0/tests/fixtures/openai_agents_unsafe.py +37 -0
  80. aigis_lint-0.2.0/tests/fixtures/raw_history_retrieval.py +21 -0
  81. aigis_lint-0.2.0/tests/fixtures/raw_history_retrieval_safe.py +10 -0
  82. aigis_lint-0.2.0/tests/fixtures/readonly_tool.py +31 -0
  83. aigis_lint-0.2.0/tests/fixtures/retry_bounded.py +22 -0
  84. aigis_lint-0.2.0/tests/fixtures/retry_unbounded.py +20 -0
  85. aigis_lint-0.2.0/tests/fixtures/safe_guarded.py +32 -0
  86. aigis_lint-0.2.0/tests/fixtures/safe_langgraph.py +14 -0
  87. aigis_lint-0.2.0/tests/fixtures/test_exclusion/src/agent.py +7 -0
  88. aigis_lint-0.2.0/tests/fixtures/test_exclusion/tests/test_agent.py +7 -0
  89. aigis_lint-0.2.0/tests/fixtures/unsafe_no_approval.py +16 -0
  90. aigis_lint-0.2.0/tests/fixtures/unsafe_no_budget.py +13 -0
  91. aigis_lint-0.2.0/tests/fixtures/unsafe_privileged.py +19 -0
  92. aigis_lint-0.2.0/tests/fixtures/user_controlled_budget.py +8 -0
  93. aigis_lint-0.2.0/tests/fixtures/user_controlled_budget_safe.py +8 -0
  94. aigis_lint-0.2.0/tests/test_analyzer.py +193 -0
  95. aigis_lint-0.2.0/tests/test_baseline.py +76 -0
  96. aigis_lint-0.2.0/tests/test_cli.py +119 -0
  97. aigis_lint-0.2.0/tests/test_output.py +153 -0
  98. aigis_lint-0.2.0/tests/test_rules.py +471 -0
  99. aigis_lint-0.2.0/tests/test_suppression.py +84 -0
@@ -0,0 +1,8 @@
1
+ # Aigis project-level configuration
2
+ #
3
+ # The examples/ directory contains intentionally unsafe code
4
+ # used for demos and documentation. Suppress findings there.
5
+
6
+ suppressions:
7
+ - path: "**/examples/**"
8
+ reason: "Demo fixtures — intentionally unsafe for documentation"
@@ -0,0 +1,30 @@
1
+ # Aigis Governance Scan
2
+ #
3
+ # Scans Python code for unsafe AI agent autonomy patterns on every push and PR.
4
+
5
+ name: Aigis Governance Scan
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ pull_request:
11
+ branches: [main]
12
+
13
+ jobs:
14
+ aigis:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install Aigis
24
+ run: pip install -e . && pip install pytest
25
+
26
+ - name: Run Aigis scan
27
+ run: aigis scan . -f console
28
+
29
+ - name: Run tests
30
+ run: python -m pytest tests/ -q
@@ -0,0 +1,23 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ *.egg
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ *.so
11
+ .env
12
+ .venv/
13
+ venv/
14
+ test-repos/
15
+ aigis-baseline.json
16
+ .claude/
17
+ .cursor/
18
+ .windsurfrules
19
+ northStar.txt
20
+ AGENTS.md
21
+ CLAUDE.md
22
+ project-state/
23
+ .github/copilot-instructions.md
File without changes
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aigis contributors
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,350 @@
1
+ Metadata-Version: 2.4
2
+ Name: aigis-lint
3
+ Version: 0.2.0
4
+ Summary: AI Execution Governance Linter — static analysis for unsafe AI autonomy
5
+ Project-URL: Homepage, https://github.com/tyreamer/aigis
6
+ Project-URL: Repository, https://github.com/tyreamer/aigis
7
+ Project-URL: Issues, https://github.com/tyreamer/aigis/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: agents,ai,governance,linter,security,static-analysis
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Security
15
+ Classifier: Topic :: Software Development :: Quality Assurance
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: pyyaml>=6.0
18
+ Requires-Dist: rich>=13.0
19
+ Requires-Dist: typer>=0.9
20
+ Description-Content-Type: text/markdown
21
+
22
+ # aigis
23
+
24
+ **Governance linting for AI agents.** Verify that your agents can't delete, execute, or exfiltrate without approval — before they ever run.
25
+
26
+ Aigis statically analyzes Python AI agent code and reports missing governance controls: approval gates on dangerous tools, consent wrappers on privileged operations, and execution budgets on agent loops. It works across LangChain, LangGraph, OpenAI Agents SDK, CrewAI, and AutoGen — with zero runtime dependencies.
27
+
28
+ > **Public Alpha (v0.2.0)** — core rules are stable and validated against real-world repos. API surface and framework coverage may evolve. [Feedback welcome.](https://github.com/tyreamer/aigis/issues)
29
+
30
+ ---
31
+
32
+ ## Why This Exists
33
+
34
+ AI agents call tools. Tools can delete files, run shell commands, and send HTTP requests. Most agent frameworks make it easy to expose these capabilities — and easy to forget the controls.
35
+
36
+ Traditional SAST finds software vulnerabilities (SQL injection, XSS). Runtime AI safety tools catch bad behavior after deployment. Neither answers the question that matters before you ship:
37
+
38
+ **Can this agent take high-impact actions without human approval, and can it run forever?**
39
+
40
+ Aigis answers that question at build time, from code alone, with no LLM required.
41
+
42
+ ## What One Scan Gives You
43
+
44
+ ```bash
45
+ $ aigis scan examples/unsafe_tool.py
46
+ ```
47
+ ```
48
+ aigis v0.2.0 - AI Execution Governance Linter
49
+ Scanning: examples/unsafe_tool.py
50
+
51
+ AIGIS001 ERROR examples/unsafe_tool.py:13:0
52
+ Tool 'run_cmd' reaches side-effecting sink(s) [subprocess.run] without an approval gate
53
+ Evidence: sink=subprocess execution | approval=no | confidence=high
54
+ Fix: Add an approval decorator or wrap side-effecting calls with a confirmation check.
55
+
56
+ AIGIS002 ERROR examples/unsafe_tool.py:13:0
57
+ Tool 'run_cmd' performs privileged operation(s) [subprocess.run] without a consent/policy wrapper
58
+ Evidence: sink=subprocess execution | approval=no | confidence=high
59
+ Fix: Add a consent/policy decorator (e.g. @requires_consent, @policy_check).
60
+
61
+ Found 2 finding(s) (2 error, 0 warning)
62
+ ```
63
+
64
+ From one scan, you get:
65
+ - Every tool that can mutate, execute, or send data — and whether it has an approval gate
66
+ - Every privileged operation (subprocess, system commands) — and whether it has a consent wrapper
67
+ - Every agent entry point — and whether it has an iteration/budget limit
68
+ - Structured evidence explaining *what* was found, *why* it matters, and *how* to fix it
69
+ - Output in console, JSON, SARIF, or a visual HTML report
70
+
71
+ ## The Code That Defines the Category
72
+
73
+ ```python
74
+ @tool
75
+ def run_cmd(cmd: str, timeout: int = 30) -> str:
76
+ """Execute a shell command."""
77
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
78
+ return result.stdout
79
+ ```
80
+
81
+ An AI agent tool that runs arbitrary shell commands with `shell=True` and agent-controlled input. No human approval. No consent policy. No iteration limit on the agent calling it.
82
+
83
+ Aigis fires both **AIGIS001** (no approval gate) and **AIGIS002** (no consent wrapper). This pattern was found in a real course repo with hundreds of forks.
84
+
85
+ ## Who This Is For
86
+
87
+ - **AI platform teams** building tool-using agents for production
88
+ - **AppSec engineers** adding agent code to their security review process
89
+ - **Architecture leads** establishing governance standards for agentic systems
90
+ - **Platform engineering** teams shipping LangGraph/CrewAI/OpenAI Agents infrastructure
91
+
92
+ Aigis is built for teams where agents interact with real systems — not toy chatbots.
93
+
94
+ ## Install
95
+
96
+ ```bash
97
+ pip install git+https://github.com/tyreamer/aigis.git
98
+ ```
99
+
100
+ Or clone and install locally:
101
+
102
+ ```bash
103
+ git clone https://github.com/tyreamer/aigis.git
104
+ cd aigis
105
+ pip install -e .
106
+ ```
107
+
108
+ ## 5-Minute Quick Start
109
+
110
+ ```bash
111
+ # Scan your agent code
112
+ aigis scan /path/to/your/project
113
+
114
+ # Scan the included examples
115
+ aigis scan examples/unsafe_tool.py # fires AIGIS001 + AIGIS002
116
+ aigis scan examples/unbounded_agent.py # fires AIGIS001 + AIGIS003
117
+ aigis scan examples/safe_agent.py # clean — no findings
118
+
119
+ # Generate a visual HTML report
120
+ aigis scan /path/to/your/project -f html -o report.html
121
+
122
+ # CI-ready outputs
123
+ aigis scan . -f json # structured JSON
124
+ aigis scan . -f sarif -o results.sarif # GitHub Code Scanning
125
+
126
+ # Baseline workflow: accept current findings, fail only on new ones
127
+ aigis baseline . -o .aigis-baseline.json
128
+ aigis scan . --baseline .aigis-baseline.json
129
+ ```
130
+
131
+ ## Rules
132
+
133
+ ### AIGIS001 — Mutating Tool Without Approval Gate
134
+
135
+ Fires when a tool performs side effects (file I/O, subprocess, HTTP mutations) with no approval mechanism.
136
+
137
+ ```python
138
+ # Flagged:
139
+ @tool
140
+ def delete_user(user_id: str):
141
+ os.remove(f"/data/{user_id}.json")
142
+
143
+ # Clean:
144
+ @tool
145
+ @requires_approval
146
+ def delete_user(user_id: str):
147
+ os.remove(f"/data/{user_id}.json")
148
+ ```
149
+
150
+ **Detected sinks:** `os.remove`, `shutil.rmtree`, `subprocess.run`, `os.system`, `requests.post`, `httpx.put`, `open()` with write mode, and more.
151
+
152
+ ### AIGIS002 — Privileged Operation Without Consent Wrapper
153
+
154
+ Fires when a tool calls subprocess or system commands without an explicit consent or policy wrapper. Generic `@requires_approval` is not sufficient — requires `@requires_consent`, `@policy_check`, or similar.
155
+
156
+ ```python
157
+ # Flagged (generic approval is not consent-level):
158
+ @tool
159
+ @requires_approval
160
+ def run_command(cmd: str):
161
+ subprocess.run(cmd, shell=True)
162
+
163
+ # Clean:
164
+ @tool
165
+ @requires_consent
166
+ def run_command(cmd: str):
167
+ subprocess.run(cmd, shell=True)
168
+ ```
169
+
170
+ ### AIGIS003 — Missing Execution Budget
171
+
172
+ Fires when an agent entry point has no iteration or budget limit — neither on the constructor nor on any execution call in the same file.
173
+
174
+ ```python
175
+ # Flagged:
176
+ agent = Agent(name="x", tools=[my_tool])
177
+ Runner.run(agent, input="go") # no max_turns anywhere
178
+
179
+ # Clean (constructor budget):
180
+ agent = AgentExecutor(agent=llm, tools=[t], max_iterations=10)
181
+
182
+ # Clean (execution-time budget):
183
+ agent = Agent(name="x", tools=[my_tool])
184
+ Runner.run(agent, input="go", max_turns=10)
185
+ ```
186
+
187
+ Aigis checks budget controls at both construction time and execution time, including `Runner.run(max_turns=N)`, `app.invoke(config={"recursion_limit": N})`, `initiate_group_chat(max_rounds=N)`, and config variable resolution.
188
+
189
+ ### AIGIS004 — Unbounded Retry / Loop
190
+
191
+ Fires when a tool contains a retry decorator without max attempts, or a `while True` loop without a break condition.
192
+
193
+ ```python
194
+ # Flagged:
195
+ @tool
196
+ @retry # no stop=, no max_retries=
197
+ def fetch_data(url: str) -> str:
198
+ return requests.post(url).text
199
+
200
+ # Clean:
201
+ @tool
202
+ @retry(stop=stop_after_attempt(3))
203
+ def fetch_data(url: str) -> str:
204
+ return requests.post(url).text
205
+ ```
206
+
207
+ ### AIGIS005 — User-Controlled Budget Without Cap
208
+
209
+ Fires when an execution budget parameter (`max_turns`, `recursion_limit`, etc.) receives its value from a variable rather than a constant, with no visible server-side cap.
210
+
211
+ ```python
212
+ # Flagged:
213
+ def run_agent(user_max_turns: int):
214
+ Runner.run(agent, input="go", max_turns=user_max_turns) # no cap
215
+
216
+ # Clean:
217
+ def run_agent(user_max_turns: int):
218
+ Runner.run(agent, input="go", max_turns=min(user_max_turns, 50))
219
+ ```
220
+
221
+ ### AIGIS006 — Raw Chat History as Retrieval Query
222
+
223
+ Fires when a raw chat history variable (`messages`, `chat_history`, `conversation`) is passed directly to a retrieval function without a query rewriting step.
224
+
225
+ ```python
226
+ # Flagged:
227
+ results = store.similarity_search(chat_history) # raw transcript as query
228
+
229
+ # Clean:
230
+ query = condense_question(chat_history)
231
+ results = store.similarity_search(query)
232
+ ```
233
+
234
+ ## Supported Frameworks
235
+
236
+ | Framework | Tool Detection | Entry Points | Budget Controls |
237
+ |-----------|---------------|-------------|-----------------|
238
+ | **LangChain** | `@tool` | `AgentExecutor` | `max_iterations`, `timeout` |
239
+ | **LangGraph** | `add_node` | `compile()` | `recursion_limit` |
240
+ | **OpenAI Agents** | `@function_tool` | `Agent()` | `max_turns` (constructor or `Runner.run`) |
241
+ | **CrewAI** | `@tool` | `Crew()` | `max_iter`, `max_rpm` |
242
+ | **AutoGen / AG2** | `register_for_llm` | `AssistantAgent`, `GroupChat` | `max_turns`, `max_round` |
243
+
244
+ ## Output Formats
245
+
246
+ | Format | Use Case | Command |
247
+ |--------|----------|---------|
248
+ | **Console** | Local development | `aigis scan .` |
249
+ | **JSON** | CI pipelines, scripting | `aigis scan . -f json` |
250
+ | **SARIF** | GitHub Code Scanning | `aigis scan . -f sarif -o results.sarif` |
251
+ | **HTML** | Reports, reviews, demos | `aigis scan . -f html -o report.html` |
252
+
253
+ The HTML report is a self-contained dark-mode file with filters, expandable evidence cards, remediation guidance, and framework-specific context. No backend required — open it in any browser.
254
+
255
+ ## Suppression
256
+
257
+ ### Inline
258
+
259
+ ```python
260
+ @tool # aigis: disable=AIGIS001 -- reviewed and accepted risk
261
+ def my_tool():
262
+ os.remove(path)
263
+ ```
264
+
265
+ ### Config File
266
+
267
+ Create `.aigis.yaml` in your project root:
268
+
269
+ ```yaml
270
+ suppressions:
271
+ - rule: AIGIS001
272
+ path: "scripts/**"
273
+ reason: "Internal tooling with runtime approval"
274
+
275
+ - rule: AIGIS003
276
+ symbol: my_agent
277
+ reason: "Budget enforced by external orchestrator"
278
+ ```
279
+
280
+ ### Baseline
281
+
282
+ Accept current findings, fail only on new ones:
283
+
284
+ ```bash
285
+ aigis baseline . -o .aigis-baseline.json
286
+ aigis scan . --baseline .aigis-baseline.json
287
+ ```
288
+
289
+ Fingerprints use rule ID + file path + tool name (not line numbers), so they survive code edits.
290
+
291
+ ## How Aigis Is Different
292
+
293
+ | | Traditional SAST | Runtime AI Safety | **Aigis** |
294
+ |---|---|---|---|
295
+ | **When** | Build time | Runtime | **Build time** |
296
+ | **What** | Software vulns (SQLi, XSS) | Model behavior, guardrails | **Agent governance controls** |
297
+ | **Checks for** | Code flaws | Harmful outputs | **Missing approval, consent, bounds** |
298
+ | **Requires runtime** | No | Yes | **No** |
299
+ | **AI/LLM needed** | No | Often | **No** |
300
+
301
+ Aigis is not a prompt scanner, a model guardrail, or a vulnerability finder. It checks whether the structural controls that should exist in agent code — approval gates, consent wrappers, execution budgets — are actually present.
302
+
303
+ ## What It Does NOT Detect
304
+
305
+ - **Cross-file call graphs** — sinks must be in the same function body as the tool
306
+ - **Data-flow analysis** — cannot track tainted inputs through variables
307
+ - **Runtime behavior** — all analysis is static and deterministic
308
+ - **SQL mutations** — `cursor.execute()` is too ambiguous without query analysis
309
+ - **Dynamic tool registration** — runtime reflection / metaprogramming
310
+ - **Non-Python code** — Python only
311
+ - **LLM-based judgment** — purely pattern-based, no semantic understanding
312
+
313
+ ## Roadmap
314
+
315
+ **What works well today:**
316
+ - Tool detection and sink analysis across 6 frameworks
317
+ - Approval/consent/budget governance checks
318
+ - Constructor-time and execution-time budget detection
319
+ - Suppression, baselines, and 4 output formats
320
+
321
+ **What's next:**
322
+ - Cross-file call graph support
323
+ - Data-flow tracking for indirect sinks
324
+ - Posture summary (aggregate governance metrics per scan)
325
+ - PyPI package publishing (`pip install aigis`)
326
+ - Published GitHub Action
327
+ - Additional framework depth (LlamaIndex, Google ADK)
328
+
329
+ **Explicitly out of scope for now:**
330
+ - TypeScript/JavaScript support
331
+ - Runtime monitoring
332
+ - LLM-based detection
333
+ - Cloud dashboard or hosted service
334
+
335
+ ## Design Principles
336
+
337
+ - **Deterministic** — code patterns only, never LLM judgment
338
+ - **Tri-state** — yes / no / unknown; unknown does not fail
339
+ - **Low noise** — false negatives over false positives
340
+ - **Missing guard is first-class** — the absence of a control is the finding
341
+ - **Evidence-first** — every finding explains what, why, and how to fix
342
+
343
+ ## Feedback
344
+
345
+ Aigis is in public alpha. If you're building tool-using agents and want governance visibility before production, we want to hear from you.
346
+
347
+ - [Open an issue](https://github.com/tyreamer/aigis/issues) with findings, false positives, or framework gaps
348
+ - [Start a discussion](https://github.com/tyreamer/aigis/discussions) about your governance workflow
349
+
350
+ We're especially interested in feedback from teams shipping agents with file access, network access, or subprocess execution.