Metadata-Version: 2.4
Name: agenticlint
Version: 0.1.0
Summary: Static linter that checks whether an OpenAPI spec is safe and clear enough to expose as MCP/AI-agent tools.
Project-URL: Homepage, https://github.com/Seo-yul/agenticlint
Project-URL: Repository, https://github.com/Seo-yul/agenticlint
Project-URL: Changelog, https://github.com/Seo-yul/agenticlint/blob/main/CHANGELOG.md
Author: axmp_ai_service
License: Apache-2.0
License-File: LICENSE
Keywords: ai-agent,linter,mcp,openapi,static-analysis
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Requires-Dist: ruamel-yaml>=0.18
Provides-Extra: cli
Requires-Dist: typer>=0.12; extra == 'cli'
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: typer>=0.12; extra == 'dev'
Description-Content-Type: text/markdown

# agenticlint

**English** | [한국어](README.ko.md)

> An OpenAPI spec being machine-readable does not make it agent-ready.

`agenticlint` is a static linter that checks whether an OpenAPI/Swagger document is
safe and clear enough to expose as **MCP / AI-agent tools** — *before* you convert it.
It flags ambiguous names, unclassified risk, missing approval policy, data-exfiltration
surfaces, and tool-poisoning vectors. **No LLM in the judgment path**: every finding is
deterministic and reproducible, so it works as a CI gate.

**Docs:** [English guide](docs/en/index.md) · [한국어 가이드](docs/ko/index.md) · [Rule reference](docs/en/rules.md)

## Install

```bash
pip install "agenticlint[cli]"   # library + full CLI
pip install agenticlint          # library only (a minimal built-in CLI still works)
pipx run agenticlint scan openapi.yaml
```

> Not yet published to PyPI; until then install from source: `pip install -e ".[cli]"`.

## Use

### CLI

```bash
agenticlint scan openapi.yaml
agenticlint scan https://api.example.com/openapi.json
agenticlint scan openapi.yaml --fail-on high --format markdown --output report.md

agenticlint baseline openapi.yaml                          # freeze the legacy backlog
agenticlint scan openapi.yaml --baseline .agenticlint-baseline.json   # only NEW findings fail
```

Exit codes: `0` pass · `1` findings at/above `--fail-on` · `2` load/config error.
Behavior is configurable via `./.agenticlint.yaml` (presets, rule on/off, thresholds,
lexicon extension, ignorePaths) — see the [guide](docs/en/index.md#configuration-agenticlintyaml).

### Library (the core is the product; the CLI is a thin wrapper)

```python
from agenticlint import scan

report = scan("openapi.yaml")     # path, http(s) URL, or a parsed dict
print(report.summary())
if not report.passed("high"):
    raise SystemExit(1)

report.to_json()      # versioned JSON contract — the cross-language interface
report.to_markdown()
```

### GitHub Actions

```yaml
- run: pipx run agenticlint scan openapi.yaml --fail-on high
```

## What it checks (49 rules across 7 families)

| Family | Concern | Examples |
| --- | --- | --- |
| **S** structure | fields missing → can't interpret/construct | `S007` risky op with no auth |
| **A** ambiguity | vague names/descriptions → wrong tool/payload | `A001` generic `id` param |
| **X** cross-op | duplicate / conflicting tools across the spec | `X001` near-identical descriptions |
| **R** risk | HTTP-semantics contradictions, dangerous surfaces | `R001` side-effect GET · `R003` collection-wide delete |
| **P** policy | declared `x-agent-policy` vs observed risk | `P001` destructive with no policy |
| **I** integrity | tool poisoning in descriptions | `I001` prompt injection · `I002` hidden chars |
| **M** MCP compat | conversion loss / degradation | `M001` invalid tool name · `M003` too many tools |

Full judgment logic and the lexicons live in the [rule reference](docs/en/rules.md); the
reasoning for why static analysis can do this is in the ["How it works" section of the
guide](docs/en/index.md#how-it-works-and-why-it-can).

## How it works

```
OpenAPI (YAML/JSON) → parse ($ref) → IR (tokenized) → risk classifier
                    → rule engine (pure functions) → report + exit code
```

The risk classifier is a weighted signal table (HTTP method baseline + lexical
override), not a model. Ambiguity is measured by proxy signals (short descriptions,
generic names, near-duplicate descriptions) — the same principle ESLint uses for "bad
code". See the [guide](docs/en/index.md#how-it-works-and-why-it-can) for what static
analysis covers vs. what stays with a human reviewer, and its
[Evidence & prior art](docs/en/index.md#evidence--prior-art) section for the research
(Hermes, AutoMCP, MetaTool, Anthropic/OpenAI tool guidance) grounding the rules.

## `x-agent-policy`

Findings suggest an OpenAPI vendor extension you attach per operation:

```yaml
x-agent-policy:
  risk: destructive          # read | write | destructive | financial | external | privilege
  requireConfirmation: true
  confirmationMessage: "Cancel order {orderId}? This cannot be undone."
  sensitiveData: false
  exposeToAgent: true
```

These map cleanly onto MCP tool annotations (`readOnlyHint`, `destructiveHint`, …),
so the same policy drives the eventual MCP conversion.

## Development

```bash
pip install -e ".[dev]"
pytest
```

The `demo/` specs are the test oracle: `shop-api-bad.yaml` must reproduce
`expected-findings.yaml` exactly, and `shop-api-good.yaml` must produce zero findings
(it embeds false-positive traps). See `demo/README.md`.

## License

Apache-2.0
