lucinlabs
CLAUDE.md1 starsChanged 3 months agoMITView on GitHub
Lucin (package: lucin, pip name lucin) is a static security scanner for AI agents. It parses agent framework code (LangChain, MCP, CrewAI, AutoGen, OpenAI Swarm, PydanticAI, Google ADK, and a generic fallback) into a normalized Agent/Tool model, runs detector rules over it, and reports OWASP-mapped findings with a 0-100 security score. control_plane/ is a separate, early-stage FastAPI SaaS scaffold built on top of the OSS engine (see control_plane/README.md). Note: CONTRIBUTING.md still refers to the package by its old name agentguard…
- Installs packages
In this repository2 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- site/llms.txtllms.txt
The file
We split this CLAUDE.md into the rules it gives an agent
4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 126
Every rule maps to an OWASP Agentic Top 10 category and cites a real-world basis where possible.
- Very specific: line 148
If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
- Very specific: line 149
Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
- Very specific: line 150
After modifying code, run graphify update .
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
Lucin (package: lucin, pip name lucin) is a static security scanner for AI agents. It parses agent
framework code (LangChain, MCP, CrewAI, AutoGen, OpenAI Swarm, PydanticAI, Google ADK, and a generic
fallback) into a normalized Agent/Tool model, runs detector rules over it, and reports OWASP-mapped
findings with a 0-100 security score. control_plane/ is a separate, early-stage FastAPI SaaS scaffold
built on top of the OSS engine (see control_plane/README.md).
Note: CONTRIBUTING.md still refers to the package by its old name agentguard and an older detector
layout — the source of truth for current structure is src/lucin/ and src/lucin/detectors/__init__.py,
not that doc.
Commands
pip install -e ".[dev]" # install with test/lint deps
pytest # run full test suite (433 passing, tests/ dir)
pytest tests/test_scanner.py # run one test file
pytest tests/test_scanner.py::test_name -q # run a single test
ruff check src/ # lint
lucin scan ./my-agent/ # core scan command
lucin scan ./my-agent/ --ci --fail-on high
lucin info ./my-agent/ # inventory without running detections
lucin redteam ./my-agent/ # targeted adversarial payloads (experimental)
lucin monitor ./traces.jsonl # behavioral anomaly scoring (experimental)
lucin serve --port 8080 # REST API (requires `.[api]` extra)
# Reproduce headline validated numbers (see README "Validated Capabilities"):
python benchmarks/build_benign_corpus.py # SCAN precision (0 FP / 52 repos)
python benchmarks/recall_corpus.py # SCAN recall (38/50 = 76%)
python benchmarks/guard_live_llm.py # GUARD live-LLM block testpyproject.toml defines the lucin console script (lucin.cli:app), ruff config
(line-length 100, py310 target), and optional extras: api (FastAPI/uvicorn for lucin serve),
behavioral (river/numpy/sklearn — required for the validated Half-Space Trees monitor backend;
without it, behavioral/streaming.py falls back to an unvalidated pure-Python implementation that
warns on use), dev (pytest/ruff).
Architecture
Pipeline: parse → detect → score → report.
target dir/file
→ parsers/* (framework-specific: langchain_parser, mcp_parser, crewai_parser,
autogen_parser, swarm_parser, pydantic_ai_parser, google_adk_parser,
llamaindex_parser, generic_parser as catch-all)
→ normalized Agent/Tool/MCPServer models (models.py)
→ scanner.scan_target() orchestrates parsing + detectors/run_all_detectors()
→ Finding objects, one per (detector, location)
→ scoring.py computes 0-100 score from findings
→ reporter.py (terminal/rich), html_report.py, sarif.py, owasp_report.py (output formats)Detector registry is the source of truth for "what runs." src/lucin/detectors/__init__.py
defines PER_AGENT_DETECTORS (analyze one agent) and CROSS_AGENT_DETECTORS (analyze relationships,
e.g. delegation chains), and ACTIVE_DETECTOR_COUNT = len(PER_AGENT_DETECTORS) + len(CROSS_AGENT_DETECTORS).
A detector module existing in detectors/ does not mean it runs — it must be imported and added to one
of those two lists. Two detectors are intentionally built but NOT registered (documented inline in that
file): detect_path_traversal (sound, but the benign corpus has byte-identical legitimate patterns —
precision over recall) and detect_memory_poisoning/AG-013 (its entry point currently return [],
disabled pending real false-positive data). When adding a new detector, register it in one of the two
lists or it silently never fires and the transparency count won't reflect it.
Taint analysis is intentionally limited, not a whole-program call graph (no PyCG on the build mirror). Layers, from what's actually wired into production scans:
- Intraprocedural, flow-sensitive, field-insensitive taint per function (
parsers/body_inspector.py,intraproc_taint) — this is what most detectors use. - Capability-based classification as the cross-function approximation: each tool is classified by capabilities it exhibits (untrusted input, shell exec, network egress, secrets access, ...), and dangerous combinations are flagged (lethal trifecta, dangerous-combination detectors) rather than proving a literal data-flow path.
- Limited cross-function/intra-class taint (
analysis/cross_function_taint.py, viadetectors/_taint.py) is wired into SSRF, insecure-deserialization, and path-traversal detectors — same-file method-to-method flows only, no cross-file or dynamic-dispatch resolution. analysis/sanitizers.pyis the kind-scoped sanitizer/barrier model (SinkKind.COMMAND/SQL/PATH/ HTML/URL), modelled on Pysa'sSanitize[TaintSink[SQL]]. It is fail-closed — an unrecognised call is treated as NOT sanitizing, so it can only ever withdraw a finding it can prove is guarded. Wired into 8 detectors plusfix.py/auto_pr.py/generic_parser.py/rule_docs.py. NOTE: it is applied at the detector level;body_inspector.py's taint engines (intraproc_taint,source_sink_taint) do not consult it, so there is no barrier semantics inside the dataflow fixpoint itself.analysis/cfg.pybuilds a real intraprocedural CFG but is imported by nothing — it was written to enable flow-sensitive taint and was never wired in. Dead code today; the enabling layer if guard-pattern taint clearing is ever added.
(Historical note: analysis/file_scope_taint.py was documented here for a long time but was
deliberately deleted — see tests/test_architecture.py "File-scope taint tests removed ... H4". Do not
plan against it; it does not exist.)
GUARD (runtime) vs SCAN (static): src/lucin/guard/ is the runtime interception/admission layer
(interceptor.py, admission.py, injection_detector.py, ifc_runtime.py, taint_registry.py,
provenance.py, adapters.py for framework runtime hooks, otel_export.py). It shares the same
lucin.aifg.AIFG engine and IFCLabel lattice as the static scanner (aifg.py) — this is called out as
a deliberate invariant in control_plane/README.md: a static finding and a runtime enforcement decision
are the same object type, not two parallel implementations that can drift.
src/lucin/prove/ is the red-team/adversarial-testing engine backing lucin redteam:
attack_library.py + payload_generator.py build targeted attacks from the agent's actual tool names,
benchmark.py drives ASR (attack success rate) evaluation.
src/lucin/behavioral/ backs lucin monitor — ML-based anomaly scoring over agent traces
(multi-model ensemble: frequency/temporal/parameter/structural/sequence), validated only on synthetic
corpora so far (see README "Validated Capabilities" for exact numbers and what's launch-gated).
src/lucin/multiagent/ covers cross-agent risks: delegation chains, memory/vector-store
poisoning detection, identity/cascade spoofing checks.
_fs.py centralizes the vendored/build directory exclusion list (venv, .venv, node_modules,
site-packages, *.dist-info, .git, dist, build, __pycache__) used by all file walks — this is
why lucin scan . doesn't flag a project's own dependencies.
control_plane/: FastAPI app (api/app.py) + Postgres/TimescaleDB models (models/) + SDK
(sdk/guard_client.py) for a hosted SaaS layer around the OSS engine. Explicitly a first-pass scaffold
with honest TODOs — read control_plane/README.md before assuming any endpoint is production-ready.
Rule-quality conventions (from CONTRIBUTING.md, still applicable)
- Detector functions take
Agentand returnlist[Finding]. - Every rule maps to an OWASP Agentic Top 10 category and cites a real-world basis where possible.
- Precision is prioritized over recall — a detector with any known false-positive path against the benign corpus should not be registered (see the path-traversal precedent above) until fixed.
- Rule IDs: current allocation is visible directly in the README's detector table and in
grep -rhoE 'id="AG-[A-Z0-9-]+"' src/lucin/detectors/*.py— treat that grep, notCONTRIBUTING.md's stale range table, as ground truth for what IDs exist.
Honesty/claims discipline
This repo is unusually strict about not overclaiming: numbers in README.md and
DEFINITION_OF_DONE.md are labeled by provenance (real repos vs. synthetic corpora vs.
launch-gated/not-yet-validated), and each ships the exact command to regenerate it. When touching
detectors, benchmarks, or README claims, keep that discipline — don't state a capability or number
without a way to reproduce it, and don't upgrade a "synthetic" or "launch-gated" label without new
evidence.
graphify
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
Rules:
- For codebase questions, first run
graphify query "<question>"when graphify-out/graph.json exists. Usegraphify path "<A>" "<B>"for relationships andgraphify explain "<concept>"for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output. - If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
- After modifying code, run
graphify update .to keep the graph current (AST-only, no API cost).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

