Skip to main content

Conservation Guardian

A Python library and CLI tool for profiling token usage and cost of workflow executions, enforcing budgets around subprocesses, and detecting wasteful LLM call patterns.

Quickstart

pip install conservation-guardian

Minimal programmatic usage:

from conservation_guardian import Profiler, NodeSample, WasteDetector, Reporter

profiler = Profiler()
profiler.record(NodeSample(
    node_id="summarizer", input_tokens=4200, output_tokens=180,
    latency_ms=820.0, cost_usd=0.015, node_title="Summarizer",
))

findings = WasteDetector(profiler).detect()
for f in findings:
    print(f"[{f.severity}] {f.message}")

CLI usage — wrap any command with a time or token budget:

conservation-guardian run --max-time-seconds 600 -- opencode exec "refactor foo.py"
conservation-guardian run --max-tokens 100000 -- aider --model gpt-4o
conservation-guardian run --max-time-seconds 300 --report run.json -- my-agent "$TASK"

Usage

1. Profile nodes programmatically

from conservation_guardian import Profiler, NodeSample

profiler = Profiler(degradation_window=10)

profiler.record(NodeSample(
    node_id="summarizer", input_tokens=4200, output_tokens=180,
    latency_ms=820.0, cost_usd=0.015, node_title="Summarizer",
))

profile = profiler.get("summarizer")
profile.run_count            # 1
profile.avg_input_tokens     # 4200.0
profile.avg_output_tokens    # 180.0
profile.avg_cost             # 0.015
profile.total_cost           # 0.015
profile.input_output_ratio   # 23.33
profile.is_degrading()       # False

Save and load:

profiler.save("profile.json")
loaded = Profiler.load("profile.json")
trends = current_profiler.compare(previous_profiler)
# → [{"metric": "cost", "direction": "worse", "detail": "..."}]

2. Apply a budget

from conservation_guardian import WorkflowBudget

budget = WorkflowBudget(
    max_tokens_per_run=500_000,
    max_cost_per_day=50.0,
    max_nodes_per_workflow=100,
    price_input_per_1k=0.03,
    price_output_per_1k=0.06,
)

if budget.is_within_budget(input_tokens=100_000, output_tokens=50_000):
    cost = budget.record_run(100_000, 50_000)

budget.daily_spend()
budget.avg_tokens_per_run()

3. Detect waste

from conservation_guardian import WasteDetector

detector = WasteDetector(
    profiler,
    max_io_ratio=15.0,
    low_utilization_threshold=0.1,
    expensive_model_ratio=0.8,
    expensive_model_min_samples=5,
    degradation_window=5,
)

findings = detector.detect()
for f in findings:
    print(f.node_id, f.category, f.severity, f.message, f.suggestion)

4. Generate reports in multiple formats

from conservation_guardian import Reporter

reporter = Reporter(
    budget=budget,
    dag=dag,
    profiler=profiler,
    findings=findings,
    workflow_name="My Workflow",
)

reporter.to_markdown()
reporter.to_json()
reporter.to_prometheus()
reporter.to_slack()

5. Parse workflow DAGs

from conservation_guardian import WorkflowDAG

dag = WorkflowDAG.from_dict(workflow_json)

dag.llm_nodes()
dag.redundant_llm_calls()
dag.dead_branches()

6. Load data from existing systems

from conservation_guardian.adapters import GenericAdapter, OpenAIAdapter, LangChainAdapter

# Generic JSON/JSONL with configurable field mapping
adapter = GenericAdapter(
    records=[{"name": "node1", "tokens_in": 100, "tokens_out": 50, "time_ms": 200}],
    field_map={
        "node_id": "name",
        "input_tokens": "tokens_in",
        "output_tokens": "tokens_out",
        "latency_ms": "time_ms",
    },
)
samples = adapter.extract_samples()

# OpenAI API responses (uses model-based pricing)
adapter = OpenAIAdapter([
    {"model": "gpt-4o", "usage": {"prompt_tokens": 1000, "completion_tokens": 200}},
])

# LangChain callback data (LLMResult dicts)
adapter = LangChainAdapter([
    {"llm_output": {"token_usage": {"prompt_tokens": 500}, "model_name": "gpt-4"}},
])

# From file
adapter = GenericAdapter(path="runs.jsonl")

How it works

The library collects per-node samples (NodeSample), each containing input/output token counts, latency, and cost. A Profiler aggregates these into per-node profiles (NodeProfile) that expose averages, totals, and trends. WasteDetector applies configurable thresholds to profiles and returns WasteFinding objects for over‑prompted nodes, low‑utilization nodes, expensive‑model concentration, and latency degradation.

The WorkflowBudget tracks running totals of tokens and cost per day; record_run checks limits before allowing execution. WorkflowDAG parses workflow JSON into a DAG and identifies redundant LLM calls and dead branches.

The CLI (conservation-guardian run) wraps an arbitrary subprocess, passes through its stdout/stderr, and enforces two independent budgets:

  • Wall‑clock timeout (--max-time-seconds): hard limit; the child is SIGTERM’d (then SIGKILL’d) and the wrapper exits 124.
  • Token budget (--max-tokens): best‑effort; the wrapper scans the child’s stdout/stderr for token‑usage patterns (OpenAI’s {"usage": {"prompt_tokens": …}}, Anthropic‑style, generic key=value, or the phrase "Tokens used: …"). When cumulative tokens exceed the limit the child is killed and the wrapper exits 125.

A --report PATH flag writes a JSON file with timestamps, exit code, kill reason, and detected token counts. Launch failures exit 126.

CLI options

Flag Enforcement Exit on exceed
--max-time-seconds N Hard — child is killed on timeout 124
--max-tokens N Best‑effort — requires child to emit token usage 125
--report PATH Writes a JSON run report —
--workflow-name NAME Labels the report for identification —

Constraints and limitations

  • Token‑limit enforcement depends on the child process printing token usage in a recognised format. It does not inspect internal API calls of the child.
  • Token detection operates on line‑by‑line output; a token count that spans a partial buffer may be missed or delayed until the next line.
  • Daily spend tracking (budget.daily_spend()) resets to zero when the process starts; it is not persisted across restarts unless manually saved/loaded.
  • The CLI currently scans for the patterns implemented in _scan_tokens; new formats must be added manually.
  • Wall‑clock timeout gives a 5‑second grace period after SIGTERM before SIGKILL is sent.
  • The library is tested on Python 3.9+.

Project structure

Module Purpose
budget.py WorkflowBudget — token/cost/node limits and daily tracking
analyzer.py WorkflowDAG — parse workflow JSON, find redundancies and dead branches
profiler.py Profiler, NodeProfile, NodeSample — per-node stats and trends
detector.py WasteDetector, WasteFinding — surface actionable waste
report.py render_report() — quick Markdown rendering
reporter.py Reporter — multi‑format reports (JSON, Prometheus, Slack)
adapters/ Data source adapters (Generic, OpenAI, LangChain)
cli.py CLI wrapper (run subcommand) for budgeting arbitrary subprocesses
exceptions.py Custom exceptions (BudgetExceededError, InvalidProfileError, AdapterError)

License

MIT. See LICENSE.

Additional documentation

Metadata

Release files for conservation-guardian 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for conservation-guardian 0.3.0
File Size Uploaded Provenance Actions
conservation_guardian-0.3.0.tar.gz 32.8 kB Without provenance Details for conservation_guardian-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for conservation-guardian 0.3.0
File Interpreter ABI Platform Actions
conservation_guardian-0.3.0-py3-none-any.whl Python 3 none any Details for conservation_guardian-0.3.0-py3-none-any.whl

Total release size: 61.2 kB

Release files / conservation_guardian-0.3.0.tar.gz

Download URL conservation_guardian-0.3.0.tar.gz
Size 32.8 kB
Tags Source
SHA-256 checksum
How to use checksums
93a433bd4e49665b7ba9928f1e39380dfb433929841df8c4fc8ce4c990baab03
BLAKE2b-256 checksum
How to use checksums
42fe6a13afe605fe3a7bfb01ca8d1414a7d369d1908734a05de810692d733f0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / conservation_guardian-0.3.0-py3-none-any.whl

Download URL conservation_guardian-0.3.0-py3-none-any.whl
Size 28.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
795fe66b7a85862c63d1a01ac5bd9014d5e8a86c582d1b44afff38d6033ec753
BLAKE2b-256 checksum
How to use checksums
2072a37761a780bfe868bcce9b1d4e1ff606202eb40399a79a3ca13944cb646b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Security for conservation-guardian 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page