agentlinter 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.
- agentlinter-0.1.1/.github/dependabot.yml +28 -0
- agentlinter-0.1.1/.github/workflows/ci.yml +32 -0
- agentlinter-0.1.1/.github/workflows/codeql.yml +24 -0
- agentlinter-0.1.1/.gitignore +18 -0
- agentlinter-0.1.1/CLAUDE.md +77 -0
- agentlinter-0.1.1/LICENSE +21 -0
- agentlinter-0.1.1/PKG-INFO +155 -0
- agentlinter-0.1.1/README.md +122 -0
- agentlinter-0.1.1/pyproject.toml +69 -0
- agentlinter-0.1.1/setup.cfg +4 -0
- agentlinter-0.1.1/src/agent_lint/__init__.py +4 -0
- agentlinter-0.1.1/src/agent_lint/__main__.py +8 -0
- agentlinter-0.1.1/src/agent_lint/cli.py +215 -0
- agentlinter-0.1.1/src/agent_lint/comparator.py +47 -0
- agentlinter-0.1.1/src/agent_lint/config.py +83 -0
- agentlinter-0.1.1/src/agent_lint/data/providers.yaml +54 -0
- agentlinter-0.1.1/src/agent_lint/estimator.py +130 -0
- agentlinter-0.1.1/src/agent_lint/exceptions.py +27 -0
- agentlinter-0.1.1/src/agent_lint/formatters.py +202 -0
- agentlinter-0.1.1/src/agent_lint/gates.py +31 -0
- agentlinter-0.1.1/src/agent_lint/licensing.py +174 -0
- agentlinter-0.1.1/src/agent_lint/linter.py +67 -0
- agentlinter-0.1.1/src/agent_lint/models.py +192 -0
- agentlinter-0.1.1/src/agent_lint/parsers/__init__.py +97 -0
- agentlinter-0.1.1/src/agent_lint/parsers/crewai.py +70 -0
- agentlinter-0.1.1/src/agent_lint/parsers/generic.py +77 -0
- agentlinter-0.1.1/src/agent_lint/parsers/gorgon.py +104 -0
- agentlinter-0.1.1/src/agent_lint/parsers/langchain.py +67 -0
- agentlinter-0.1.1/src/agent_lint/pricing.py +123 -0
- agentlinter-0.1.1/src/agent_lint/rules/__init__.py +58 -0
- agentlinter-0.1.1/src/agent_lint/rules/budget.py +119 -0
- agentlinter-0.1.1/src/agent_lint/rules/efficiency.py +158 -0
- agentlinter-0.1.1/src/agent_lint/rules/resilience.py +150 -0
- agentlinter-0.1.1/src/agent_lint/rules/security.py +133 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/PKG-INFO +155 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/SOURCES.txt +51 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/dependency_links.txt +1 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/entry_points.txt +2 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/requires.txt +9 -0
- agentlinter-0.1.1/src/agentlinter.egg-info/top_level.txt +1 -0
- agentlinter-0.1.1/tests/__init__.py +0 -0
- agentlinter-0.1.1/tests/conftest.py +245 -0
- agentlinter-0.1.1/tests/test_cli.py +102 -0
- agentlinter-0.1.1/tests/test_comparator.py +54 -0
- agentlinter-0.1.1/tests/test_estimator.py +181 -0
- agentlinter-0.1.1/tests/test_formatters.py +155 -0
- agentlinter-0.1.1/tests/test_gates.py +74 -0
- agentlinter-0.1.1/tests/test_licensing.py +208 -0
- agentlinter-0.1.1/tests/test_linter.py +107 -0
- agentlinter-0.1.1/tests/test_models.py +255 -0
- agentlinter-0.1.1/tests/test_parsers.py +180 -0
- agentlinter-0.1.1/tests/test_pricing.py +122 -0
- agentlinter-0.1.1/tests/test_rules.py +472 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
day: "monday"
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
labels:
|
|
10
|
+
- "dependencies"
|
|
11
|
+
- "python"
|
|
12
|
+
commit-message:
|
|
13
|
+
prefix: "deps"
|
|
14
|
+
groups:
|
|
15
|
+
python-minor:
|
|
16
|
+
update-types:
|
|
17
|
+
- "minor"
|
|
18
|
+
- "patch"
|
|
19
|
+
- package-ecosystem: "github-actions"
|
|
20
|
+
directory: "/"
|
|
21
|
+
schedule:
|
|
22
|
+
interval: "weekly"
|
|
23
|
+
open-pull-requests-limit: 5
|
|
24
|
+
labels:
|
|
25
|
+
- "dependencies"
|
|
26
|
+
- "ci"
|
|
27
|
+
commit-message:
|
|
28
|
+
prefix: "ci"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
- uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- run: pip install ruff
|
|
18
|
+
- run: ruff check src/ tests/
|
|
19
|
+
- run: ruff format --check src/ tests/
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
matrix:
|
|
25
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
- uses: actions/setup-python@v6
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
- run: pip install -e ".[dev]"
|
|
32
|
+
- run: pytest tests/ -v
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CodeQL Security Scan
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 6 * * 1'
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
analyze:
|
|
13
|
+
name: Analyze
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
security-events: write
|
|
17
|
+
contents: read
|
|
18
|
+
actions: read
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- uses: github/codeql-action/init@v4
|
|
22
|
+
with:
|
|
23
|
+
languages: python
|
|
24
|
+
- uses: github/codeql-action/analyze@v4
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# CLAUDE.md — agent-lint
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
CLI tool that analyzes agent workflow YAML configs for cost estimation, anti-pattern detection (linting), and multi-provider comparison. Supports Gorgon/Forge, CrewAI, LangChain/LangGraph, and generic YAML formats.
|
|
5
|
+
|
|
6
|
+
## Quick Start
|
|
7
|
+
```bash
|
|
8
|
+
cd /home/arete/projects/agent-lint
|
|
9
|
+
source .venv/bin/activate
|
|
10
|
+
pip install -e ".[dev]"
|
|
11
|
+
pytest tests/ -v
|
|
12
|
+
ruff check src/ tests/ && ruff format --check src/ tests/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
- **src layout**: `src/agent_lint/` with 15 modules across 4 packages
|
|
17
|
+
- **Entry point**: `agent-lint = "agent_lint.cli:app"` (Typer)
|
|
18
|
+
- **Models**: Pydantic v2 (`models.py`)
|
|
19
|
+
- **Parsers**: Strategy pattern — `detect_format()` dispatches to format-specific parser
|
|
20
|
+
- **Estimator**: 3-tier token resolution (declared → archetype → default), bundled pricing YAML
|
|
21
|
+
- **Linter**: `@lint_rule` decorator registry, 17 rules across 4 categories
|
|
22
|
+
- **Licensing**: HMAC-checksum keys, prefix `ALNT`, salt `agent-lint-v1`
|
|
23
|
+
|
|
24
|
+
## Key Commands
|
|
25
|
+
```bash
|
|
26
|
+
agent-lint estimate workflow.yaml # Cost estimate (table)
|
|
27
|
+
agent-lint estimate workflow.yaml --json # JSON output
|
|
28
|
+
agent-lint estimate workflow.yaml --format markdown # Markdown output
|
|
29
|
+
agent-lint estimate workflow.yaml --provider ollama # Override provider
|
|
30
|
+
agent-lint lint workflow.yaml # Lint for anti-patterns
|
|
31
|
+
agent-lint lint workflow.yaml --category budget # Filter by category
|
|
32
|
+
agent-lint lint workflow.yaml --fail-under 80 # CI mode (exit 1 if below)
|
|
33
|
+
agent-lint compare workflow.yaml # Multi-provider comparison (Pro)
|
|
34
|
+
agent-lint status # Show license tier
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Workflow Formats
|
|
38
|
+
| Format | Detection | Key Structure |
|
|
39
|
+
|--------|-----------|---------------|
|
|
40
|
+
| Gorgon | `steps[].type` in known set | claude_code, openai, shell, parallel, etc. |
|
|
41
|
+
| CrewAI | `agents` + `tasks` top-level | Agent definitions + task assignments |
|
|
42
|
+
| LangChain | `nodes` or `edges` | Graph-based node definitions |
|
|
43
|
+
| Generic | Fallback | Any YAML with step-like structures |
|
|
44
|
+
|
|
45
|
+
## Lint Rules (17 total)
|
|
46
|
+
| Category | Rules | IDs |
|
|
47
|
+
|----------|-------|-----|
|
|
48
|
+
| Budget | Missing budgets, over-budget | B001-B004 |
|
|
49
|
+
| Resilience | Missing handlers, no retries | R001-R005 |
|
|
50
|
+
| Efficiency | Parallelization, redundancy | E001-E004 |
|
|
51
|
+
| Security | Injection, hardcoded paths | S001-S004 |
|
|
52
|
+
|
|
53
|
+
## Token Estimation Strategy
|
|
54
|
+
Resolution order per step:
|
|
55
|
+
1. `estimated_tokens` from YAML → source: "declared"
|
|
56
|
+
2. `ROLE_TOKEN_DEFAULTS[role]` → source: "archetype"
|
|
57
|
+
3. `STEP_TYPE_TOKEN_DEFAULTS[step_type]` → source: "default"
|
|
58
|
+
|
|
59
|
+
## Monetization
|
|
60
|
+
| Feature | Free | Pro ($8/mo) |
|
|
61
|
+
|---------|------|-------------|
|
|
62
|
+
| estimate | Yes | Yes |
|
|
63
|
+
| lint | Yes | Yes |
|
|
64
|
+
| status | Yes | Yes |
|
|
65
|
+
| compare | No | Yes |
|
|
66
|
+
| markdown_export | No | Yes |
|
|
67
|
+
| custom_pricing | No | Yes |
|
|
68
|
+
|
|
69
|
+
## Testing
|
|
70
|
+
- 193 tests, pytest
|
|
71
|
+
- `tests/conftest.py` has sample workflow YAML fixtures
|
|
72
|
+
- All parsers tested via fixture files
|
|
73
|
+
|
|
74
|
+
## Conventions
|
|
75
|
+
- Python 3.11+, `from __future__ import annotations` everywhere
|
|
76
|
+
- Ruff lint + format (B008 suppressed for cli.py — Typer pattern)
|
|
77
|
+
- Dependencies: typer, rich, pydantic, pyyaml
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AreteDriver
|
|
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,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentlinter
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Estimate costs and lint agent workflow YAML files
|
|
5
|
+
Author: AreteDriver
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AreteDriver/agent-lint
|
|
8
|
+
Project-URL: Repository, https://github.com/AreteDriver/agent-lint
|
|
9
|
+
Project-URL: Issues, https://github.com/AreteDriver/agent-lint/issues
|
|
10
|
+
Keywords: ai,agents,workflow,cost,linter,claude,openai,ollama
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: typer>=0.9.0
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0
|
|
27
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# agent-lint
|
|
35
|
+
|
|
36
|
+
[](https://github.com/AreteDriver/agent-lint/actions/workflows/ci.yml)
|
|
37
|
+
[](https://github.com/AreteDriver/agent-lint/actions/workflows/codeql.yml)
|
|
38
|
+
[](https://www.python.org/downloads/)
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
|
|
41
|
+
**Catch expensive agent pipelines before they run.**
|
|
42
|
+
|
|
43
|
+
`agent-lint` is the eslint of agent workflows. It reads your YAML configs, flags structural problems, and tells you what a run will cost — before you press enter.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
$ agent-lint lint workflow.yaml
|
|
47
|
+
|
|
48
|
+
3 steps validated
|
|
49
|
+
[warn] step 2: model=claude-opus-4-6 — consider claude-sonnet-4-6 (~$0.18 -> ~$0.02 per run)
|
|
50
|
+
[warn] step 3: no max_tokens set — cost unbounded
|
|
51
|
+
[fail] step 1: missing fallback handler — silent failure risk
|
|
52
|
+
|
|
53
|
+
Score: 62/100
|
|
54
|
+
|
|
55
|
+
$ agent-lint estimate workflow.yaml
|
|
56
|
+
|
|
57
|
+
Step 1 researcher claude-sonnet-4-6 ~4,200 tokens $0.02
|
|
58
|
+
Step 2 writer claude-opus-4-6 ~8,800 tokens $0.18
|
|
59
|
+
Step 3 reviewer claude-sonnet-4-6 ~3,100 tokens $0.01
|
|
60
|
+
──────────────────────────────────────────────────────────────────
|
|
61
|
+
Total ~16,100 tokens $0.21
|
|
62
|
+
Monthly (3x/day) ~$19
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
No proxies. No SDK integration. Just point it at your workflow file.
|
|
66
|
+
|
|
67
|
+
## Install
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install agent-lint
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Why
|
|
74
|
+
|
|
75
|
+
Every agent framework lets you *run* workflows. None of them tell you what it will cost before you do. You find out three days later when the invoice arrives.
|
|
76
|
+
|
|
77
|
+
`agent-lint` catches the problems that don't show up in testing:
|
|
78
|
+
|
|
79
|
+
- The step using Opus when Sonnet would do
|
|
80
|
+
- The loop with no max_tokens that could run up a $200 bill
|
|
81
|
+
- The missing error handler that silently retries (and silently bills)
|
|
82
|
+
- The hardcoded path that works on your machine and nowhere else
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Estimate costs for a workflow
|
|
88
|
+
agent-lint estimate workflow.yaml
|
|
89
|
+
agent-lint estimate workflow.yaml --provider openai
|
|
90
|
+
agent-lint estimate workflow.yaml --json
|
|
91
|
+
|
|
92
|
+
# Lint for anti-patterns
|
|
93
|
+
agent-lint lint workflow.yaml
|
|
94
|
+
agent-lint lint workflow.yaml --fail-under 80 # CI gate
|
|
95
|
+
|
|
96
|
+
# Compare providers side-by-side (Pro)
|
|
97
|
+
agent-lint compare workflow.yaml
|
|
98
|
+
|
|
99
|
+
# Check license status
|
|
100
|
+
agent-lint status
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Supported Formats
|
|
104
|
+
|
|
105
|
+
| Format | Detection |
|
|
106
|
+
|--------|-----------|
|
|
107
|
+
| Gorgon/Forge | `steps[].type` matches known step types |
|
|
108
|
+
| CrewAI | `agents` + `tasks` top-level keys |
|
|
109
|
+
| LangChain/LangGraph | `nodes` or `edges` structure |
|
|
110
|
+
| Generic | Any YAML with step-like structures |
|
|
111
|
+
|
|
112
|
+
## Lint Rules
|
|
113
|
+
|
|
114
|
+
17 rules across 4 categories:
|
|
115
|
+
|
|
116
|
+
| Category | What it catches | IDs |
|
|
117
|
+
|----------|----------------|-----|
|
|
118
|
+
| **Budget** | Missing budgets, unbounded costs, over-budget steps | B001-B004 |
|
|
119
|
+
| **Resilience** | Missing error handlers, no retries, no timeouts | R001-R005 |
|
|
120
|
+
| **Efficiency** | Missed parallelization, redundant steps | E001-E004 |
|
|
121
|
+
| **Security** | Prompt injection risk, hardcoded paths/secrets | S001-S004 |
|
|
122
|
+
|
|
123
|
+
## How It Compares
|
|
124
|
+
|
|
125
|
+
| | Pre-run cost estimate | Workflow linting | No proxy required | CLI-native |
|
|
126
|
+
|---|:---:|:---:|:---:|:---:|
|
|
127
|
+
| **agent-lint** | Yes | Yes | Yes | Yes |
|
|
128
|
+
| Langfuse | No (post-run) | No | No (SDK required) | No |
|
|
129
|
+
| Datadog LLM Observability | No (post-run) | No | No (agent required) | No |
|
|
130
|
+
| Manual review | No | No | Yes | -- |
|
|
131
|
+
|
|
132
|
+
## CI Integration
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# .github/workflows/agent-lint.yml
|
|
136
|
+
- name: Lint agent workflows
|
|
137
|
+
run: agent-lint lint workflows/ --fail-under 80
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Exits non-zero when the health score drops below your threshold.
|
|
141
|
+
|
|
142
|
+
## Free vs Pro
|
|
143
|
+
|
|
144
|
+
| Feature | Free | Pro |
|
|
145
|
+
|---------|:---:|:---:|
|
|
146
|
+
| Cost estimation | Yes | Yes |
|
|
147
|
+
| Lint (17 rules) | Yes | Yes |
|
|
148
|
+
| JSON output | Yes | Yes |
|
|
149
|
+
| Multi-provider comparison | -- | Yes |
|
|
150
|
+
| Markdown export | -- | Yes |
|
|
151
|
+
| Custom pricing tables | -- | Yes |
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# agent-lint
|
|
2
|
+
|
|
3
|
+
[](https://github.com/AreteDriver/agent-lint/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/AreteDriver/agent-lint/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
**Catch expensive agent pipelines before they run.**
|
|
9
|
+
|
|
10
|
+
`agent-lint` is the eslint of agent workflows. It reads your YAML configs, flags structural problems, and tells you what a run will cost — before you press enter.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
$ agent-lint lint workflow.yaml
|
|
14
|
+
|
|
15
|
+
3 steps validated
|
|
16
|
+
[warn] step 2: model=claude-opus-4-6 — consider claude-sonnet-4-6 (~$0.18 -> ~$0.02 per run)
|
|
17
|
+
[warn] step 3: no max_tokens set — cost unbounded
|
|
18
|
+
[fail] step 1: missing fallback handler — silent failure risk
|
|
19
|
+
|
|
20
|
+
Score: 62/100
|
|
21
|
+
|
|
22
|
+
$ agent-lint estimate workflow.yaml
|
|
23
|
+
|
|
24
|
+
Step 1 researcher claude-sonnet-4-6 ~4,200 tokens $0.02
|
|
25
|
+
Step 2 writer claude-opus-4-6 ~8,800 tokens $0.18
|
|
26
|
+
Step 3 reviewer claude-sonnet-4-6 ~3,100 tokens $0.01
|
|
27
|
+
──────────────────────────────────────────────────────────────────
|
|
28
|
+
Total ~16,100 tokens $0.21
|
|
29
|
+
Monthly (3x/day) ~$19
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
No proxies. No SDK integration. Just point it at your workflow file.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install agent-lint
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Why
|
|
41
|
+
|
|
42
|
+
Every agent framework lets you *run* workflows. None of them tell you what it will cost before you do. You find out three days later when the invoice arrives.
|
|
43
|
+
|
|
44
|
+
`agent-lint` catches the problems that don't show up in testing:
|
|
45
|
+
|
|
46
|
+
- The step using Opus when Sonnet would do
|
|
47
|
+
- The loop with no max_tokens that could run up a $200 bill
|
|
48
|
+
- The missing error handler that silently retries (and silently bills)
|
|
49
|
+
- The hardcoded path that works on your machine and nowhere else
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Estimate costs for a workflow
|
|
55
|
+
agent-lint estimate workflow.yaml
|
|
56
|
+
agent-lint estimate workflow.yaml --provider openai
|
|
57
|
+
agent-lint estimate workflow.yaml --json
|
|
58
|
+
|
|
59
|
+
# Lint for anti-patterns
|
|
60
|
+
agent-lint lint workflow.yaml
|
|
61
|
+
agent-lint lint workflow.yaml --fail-under 80 # CI gate
|
|
62
|
+
|
|
63
|
+
# Compare providers side-by-side (Pro)
|
|
64
|
+
agent-lint compare workflow.yaml
|
|
65
|
+
|
|
66
|
+
# Check license status
|
|
67
|
+
agent-lint status
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Supported Formats
|
|
71
|
+
|
|
72
|
+
| Format | Detection |
|
|
73
|
+
|--------|-----------|
|
|
74
|
+
| Gorgon/Forge | `steps[].type` matches known step types |
|
|
75
|
+
| CrewAI | `agents` + `tasks` top-level keys |
|
|
76
|
+
| LangChain/LangGraph | `nodes` or `edges` structure |
|
|
77
|
+
| Generic | Any YAML with step-like structures |
|
|
78
|
+
|
|
79
|
+
## Lint Rules
|
|
80
|
+
|
|
81
|
+
17 rules across 4 categories:
|
|
82
|
+
|
|
83
|
+
| Category | What it catches | IDs |
|
|
84
|
+
|----------|----------------|-----|
|
|
85
|
+
| **Budget** | Missing budgets, unbounded costs, over-budget steps | B001-B004 |
|
|
86
|
+
| **Resilience** | Missing error handlers, no retries, no timeouts | R001-R005 |
|
|
87
|
+
| **Efficiency** | Missed parallelization, redundant steps | E001-E004 |
|
|
88
|
+
| **Security** | Prompt injection risk, hardcoded paths/secrets | S001-S004 |
|
|
89
|
+
|
|
90
|
+
## How It Compares
|
|
91
|
+
|
|
92
|
+
| | Pre-run cost estimate | Workflow linting | No proxy required | CLI-native |
|
|
93
|
+
|---|:---:|:---:|:---:|:---:|
|
|
94
|
+
| **agent-lint** | Yes | Yes | Yes | Yes |
|
|
95
|
+
| Langfuse | No (post-run) | No | No (SDK required) | No |
|
|
96
|
+
| Datadog LLM Observability | No (post-run) | No | No (agent required) | No |
|
|
97
|
+
| Manual review | No | No | Yes | -- |
|
|
98
|
+
|
|
99
|
+
## CI Integration
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
# .github/workflows/agent-lint.yml
|
|
103
|
+
- name: Lint agent workflows
|
|
104
|
+
run: agent-lint lint workflows/ --fail-under 80
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Exits non-zero when the health score drops below your threshold.
|
|
108
|
+
|
|
109
|
+
## Free vs Pro
|
|
110
|
+
|
|
111
|
+
| Feature | Free | Pro |
|
|
112
|
+
|---------|:---:|:---:|
|
|
113
|
+
| Cost estimation | Yes | Yes |
|
|
114
|
+
| Lint (17 rules) | Yes | Yes |
|
|
115
|
+
| JSON output | Yes | Yes |
|
|
116
|
+
| Multi-provider comparison | -- | Yes |
|
|
117
|
+
| Markdown export | -- | Yes |
|
|
118
|
+
| Custom pricing tables | -- | Yes |
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "setuptools-scm>=8.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agentlinter"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Estimate costs and lint agent workflow YAML files"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [{name = "AreteDriver"}]
|
|
13
|
+
keywords = ["ai", "agents", "workflow", "cost", "linter", "claude", "openai", "ollama"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Software Development :: Build Tools",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"typer>=0.9.0",
|
|
28
|
+
"rich>=13.0",
|
|
29
|
+
"pydantic>=2.0",
|
|
30
|
+
"pyyaml>=6.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=7.0",
|
|
36
|
+
"mypy>=1.0",
|
|
37
|
+
"ruff>=0.1.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
agent-lint = "agent_lint.cli:app"
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/AreteDriver/agent-lint"
|
|
45
|
+
Repository = "https://github.com/AreteDriver/agent-lint"
|
|
46
|
+
Issues = "https://github.com/AreteDriver/agent-lint/issues"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
where = ["src"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
agent_lint = ["data/*.yaml"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 100
|
|
56
|
+
target-version = "py311"
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint.per-file-ignores]
|
|
62
|
+
"src/agent_lint/cli.py" = ["B008"]
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
66
|
+
|
|
67
|
+
[tool.mypy]
|
|
68
|
+
python_version = "3.11"
|
|
69
|
+
strict = true
|