Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ policy:
max_tokens: 256
```

Already have a CLAUDE.md? Generate a policy from it — the generator extracts your behavioral rules (skipping build commands and repo trivia) and emits a ready-to-load `SimpleLLMPolicy` config, with each rule tagged with its source line:

```bash
uv run python -m luthien_proxy.policy_generation.claude_md CLAUDE.md -o config/claude_md_policy.yaml
```

See [Generate a Policy from Your CLAUDE.md](docs/policies.md#generate-a-policy-from-your-claudemd) for details.

### Built-in Presets

Ready-to-use policies in `src/luthien_proxy/policies/presets/` — no configuration needed.
Expand Down
6 changes: 6 additions & 0 deletions changelog.d/policy-from-claude-md.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Features
pr: 802
---

**Generate a policy from CLAUDE.md**: new `uv run python -m luthien_proxy.policy_generation.claude_md <path>` command extracts enforceable behavioral rules from an existing CLAUDE.md / AGENTS.md and emits a ready-to-load `SimpleLLMPolicy` YAML, with every rule tagged with its source line and the output round-trip validated through the policy loader
35 changes: 35 additions & 0 deletions docs/policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,41 @@ policy:

---

## Generate a Policy from Your CLAUDE.md

If your project already has a CLAUDE.md (or AGENTS.md), you can turn its behavioral rules into a working policy in one step:

```bash
uv run python -m luthien_proxy.policy_generation.claude_md CLAUDE.md -o config/claude_md_policy.yaml
export POLICY_CONFIG=config/claude_md_policy.yaml
```

The generator extracts enforceable rules (lines with normative language like "never", "always", "must", "avoid", "prefer") while skipping code blocks, build commands, and repo trivia. It emits a `SimpleLLMPolicy` config whose judge checks every response against those rules. Extraction is deterministic — no LLM call, no credentials needed at generation time.

Every rule in the generated YAML is tagged with its source line, so judge decisions trace back to your CLAUDE.md:

```yaml
instructions: |-
...
1. [CLAUDE.md:171] Formatting via Ruff: double quotes, spaces for indent.
2. [CLAUDE.md:208] IMPORTANT: Always write unit tests when adding or significantly modifying code.
...
```

Options:

- `-o / --output` — write to a file (default: stdout)
- `--model` — judge model (default: `claude-haiku-4-5`)
- `--on-error pass|block` — what happens when the judge call fails (default: `pass`)
- `--max-rule-chars` — skip rules longer than this many characters (default: 400; skips are reported on stderr)
- `--no-validate` — skip the round-trip check through the policy loader

The generated file is a starting point — edit the instructions freely; it's plain `SimpleLLMPolicy` YAML.

**Trust note:** extracted rules go verbatim into the judge's instructions, so the generated policy is only as trustworthy as the CLAUDE.md it came from. Review CLAUDE.md changes with the same care as policy changes — text added to CLAUDE.md (e.g. via a malicious PR) becomes judge instructions the next time you regenerate.

---

## Quick Start Presets

Ready-to-use policies with zero configuration. Each wraps `SimpleLLMPolicy` with hardcoded instructions — just set the class and go.
Expand Down
12 changes: 12 additions & 0 deletions src/luthien_proxy/policy_generation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Utilities that generate Luthien policy YAML from external sources.

Currently supports generating a `SimpleLLMPolicy` configuration from a
project's CLAUDE.md / AGENTS.md file (`claude_md` module). Run it with:

uv run python -m luthien_proxy.policy_generation.claude_md path/to/CLAUDE.md

Note: this package intentionally avoids importing submodules at package level
so `python -m luthien_proxy.policy_generation.claude_md` runs without a
double-import warning. Import from `luthien_proxy.policy_generation.claude_md`
directly.
"""
6 changes: 6 additions & 0 deletions src/luthien_proxy/policy_generation/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Allow `python -m luthien_proxy.policy_generation <path>` as a shorthand."""

from luthien_proxy.policy_generation.claude_md import main

if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading