Metadata-Version: 2.5
Name: contextos-auditor
Version: 0.2.1
Summary: Local-first token usage auditing and estimated costs for CrewAI, LangGraph, AutoGen and OpenAI Agents SDK. No signup; optional opt-in OpenTelemetry export. Free for commercial use under PolyForm Shield 1.0.0; see LICENSE.
Project-URL: Homepage, https://github.com/surajJha/contextOS-auditor
Project-URL: Repository, https://github.com/surajJha/contextOS-auditor
Project-URL: Issues, https://github.com/surajJha/contextOS-auditor/issues
Project-URL: Changelog, https://github.com/surajJha/contextOS-auditor/blob/main/CHANGELOG.md
Author: ContextOS contributors
License: PolyForm Shield License 1.0.0
        
        <https://polyformproject.org/licenses/shield/1.0.0>
        
        Required Notice: Copyright Suraj Jha (https://github.com/surajJha)
        
        Licensor Line of Business: ContextOS agent token/cost auditing and
        optimisation tooling (contextos-auditor, contextos-optimiser)
        
        Plain-English summary (not a substitute for the terms below): you may use
        this software for **any** purpose, including inside a commercial company
        and on commercial products, free of charge. You may modify it and
        redistribute it. The one thing you may not do is use it to provide a
        product that competes with ContextOS.
        
        ## Acceptance
        
        In order to get any license under these terms, you must agree to them as
        both strict obligations and conditions to all your licenses.
        
        ## Copyright License
        
        The licensor grants you a copyright license for the software to do
        everything you might do with the software that would otherwise infringe
        the licensor's copyright in it for any permitted purpose. However, you may
        only distribute the software according to Distribution License and make
        changes or new works based on the software according to Changes and New
        Works License.
        
        ## Distribution License
        
        The licensor grants you an additional copyright license to distribute
        copies of the software. Your license to distribute covers distributing the
        software with changes and new works permitted by Changes and New Works
        License.
        
        ## Notices
        
        You must ensure that anyone who gets a copy of any part of the software
        from you also gets a copy of these terms or the URL for them above, as
        well as copies of any plain-text lines beginning with `Required Notice:`
        that the licensor provided with the software. For example:
        
        > Required Notice: Copyright Suraj Jha (https://github.com/surajJha)
        
        ## Changes and New Works License
        
        The licensor grants you an additional copyright license to make changes
        and new works based on the software for any permitted purpose.
        
        ## Patent License
        
        The licensor grants you a patent license for the software that covers
        patent claims the licensor can license, or becomes able to license, that
        you would infringe by using the software.
        
        ## Noncompete
        
        Any purpose is a permitted purpose, except for providing any product that
        competes with the software or any product the licensor or any of its
        affiliates provides using the software.
        
        ## Competition
        
        Goods and services compete even when they provide functionality through
        different kinds of interfaces or for different technical platforms.
        Applications can compete with services, libraries with plugins, frameworks
        with development tools, and so on, even if they're written in different
        programming languages or for different computer architectures. Goods and
        services compete even when provided free of charge. If you market a
        product as a practical substitute for the software or another product, it
        definitely competes.
        
        ## New Products
        
        If you are using the software to provide a product that does not compete,
        but the licensor or any of its affiliates brings your product into
        competition by providing a new version of the software or another product
        using the software, you may continue using versions of the software
        available under these terms beforehand to provide your competing product,
        but not any later versions.
        
        ## Discontinued Products
        
        You may begin using the software to compete with a product or service that
        the licensor or any of its affiliates has stopped providing, unless the
        licensor includes a plain-text line beginning with `Licensor Line of
        Business:` with the software that mentions that line of business.
        
        ## Sales of Business
        
        If the licensor or any of its affiliates sells a line of business
        developing the software or using the software to provide a product, the
        buyer can also enforce Noncompete for that product.
        
        ## Fair Use
        
        You may have "fair use" rights for the software under the law. These terms
        do not limit them.
        
        ## No Other Rights
        
        These terms do not allow you to sublicense or transfer any of your
        licenses to anyone else, or prevent the licensor from granting licenses to
        anyone else. These terms do not imply any other licenses.
        
        ## Patent Defense
        
        If you make any written claim that the software infringes or contributes
        to infringement of any patent, your patent license for the software
        granted under these terms ends immediately. If your company makes such a
        claim, your patent license ends immediately for work on behalf of your
        company.
        
        ## Violations
        
        The first time you are notified in writing that you have violated any of
        these terms, or done anything with the software not covered by your
        licenses, your licenses can nonetheless continue if you come into full
        compliance with these terms, and take practical steps to correct past
        violations, within 32 days of receiving notice. Otherwise, all your
        licenses end immediately.
        
        ## No Liability
        
        ***As far as the law allows, the software comes as is, without any
        warranty or condition, and the licensor will not be liable to you for any
        damages arising out of these terms or the use or nature of the software,
        under any kind of legal claim.***
        
        ## Definitions
        
        The **licensor** is the individual or entity offering these terms, and the
        **software** is the software the licensor makes available under these
        terms.
        
        A **product** can be a good or service, or a combination of them.
        
        **You** refers to the individual or entity agreeing to these terms.
        
        **Your company** is any legal entity, sole proprietorship, or other kind of
        organization that you work for, plus all its affiliates.
        
        **Affiliates** means the other organizations that an organization has
        control over, is under the control of, or is under common control with.
        
        **Control** means ownership of substantially all the assets of an entity,
        or the power to direct its management and policies by vote, contract, or
        otherwise. Control can be direct or indirect.
        
        **Your licenses** are all the licenses granted to you for the software
        under these terms.
        
        **Use** means anything you do with the software requiring one of your
        licenses.
License-File: LICENSE
Keywords: agents,autogen,cost,crewai,langgraph,llm,observability,openai-agents,tokens
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
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: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: autogen-core>=0.4; extra == 'all'
Requires-Dist: crewai>=0.100; extra == 'all'
Requires-Dist: langchain-core>=0.3; extra == 'all'
Requires-Dist: openai-agents>=0.1; extra == 'all'
Requires-Dist: tiktoken>=0.7; extra == 'all'
Provides-Extra: autogen
Requires-Dist: autogen-core>=0.4; extra == 'autogen'
Provides-Extra: crewai
Requires-Dist: crewai>=0.100; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: langgraph
Requires-Dist: langchain-core>=0.3; extra == 'langgraph'
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.1; extra == 'openai-agents'
Provides-Extra: otel
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20; extra == 'otel'
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'otel'
Provides-Extra: tiktoken
Requires-Dist: tiktoken>=0.7; extra == 'tiktoken'
Description-Content-Type: text/markdown

# contextos-auditor

[![PyPI](https://img.shields.io/pypi/v/contextos-auditor.svg)](https://pypi.org/project/contextos-auditor/)
[![Python](https://img.shields.io/pypi/pyversions/contextos-auditor.svg)](https://pypi.org/project/contextos-auditor/)
[![License: PolyForm Shield](https://img.shields.io/badge/license-PolyForm%20Shield%201.0.0-blue.svg)](https://github.com/surajJha/contextOS-auditor/blob/main/LICENSE)

The free, local-first Agent Auditor. Attach an adapter to
an existing CrewAI / LangGraph / AutoGen / OpenAI Agents SDK agent and
watch reported token usage and estimated cost live — no signup,
no hosted account. **Recording stays local by default; optional OTel export
sends spans to an endpoint you configure.** Your agent's own provider calls
are separate. Licensed
[PolyForm Shield](https://github.com/surajJha/contextOS-auditor/blob/main/LICENSE) — free for **any** use, including commercial
use inside your company; the only restriction is that you can't use it to
build a competing product.

> **Upgrading from 0.2.0?** Version 0.2.1 includes recording, accounting,
> streaming and Windows fixes that were missing from the 0.2.0 artifact.
> Run `python -m pip install --upgrade contextos-auditor` in your agent's
> environment and check `contextos-auditor --version`. Validate your own
> framework and recorded totals before production use; savings remain estimates.

```bash
python3 -m venv .venv
source .venv/bin/activate            # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install contextos-auditor
contextos-auditor demo --serve       # see it work, no agent required
```

![The auditor dashboard filling up as an agent runs](https://raw.githubusercontent.com/surajJha/contextOS-auditor/main/docs/demo.gif)

*Six turns of a synthetic session. Waste appears as the agent re-reads files it
had already read. Generated by `contextos-auditor demo` — no agent, no API key,
no network.*

That runs a synthetic session through the real analysis and opens the
dashboard on `127.0.0.1` — no agent, no API key, no network, nothing
written outside the current directory. It's the fastest way to see what
this actually produces before wiring it into anything.

When you're ready to point it at your own agent:

```bash
python -m pip install "contextos-auditor[crewai]"  # or [langgraph] / [autogen] / [openai-agents]
contextos-auditor doctor                     # prints the one-line snippet for your framework
```

Install into the **same environment that runs your agent**. If its SDK is
already installed, the base `contextos-auditor` package is enough.
Quote extras (`"contextos-auditor[crewai]"`), especially in zsh.

The base CLI requires Python >= 3.10 and has zero required runtime
dependencies. Frameworks impose their own Python/platform constraints;
this does not mean every extra works on every Python >= 3.10.
Python 3.11 or 3.12 is a practical starting point for a new agent environment.
Use your framework's supported Python version for an existing project.
For example, CrewAI 1.15.21 requires Python >= 3.10 and < 3.14:
`[crewai]` and `[all]` cannot currently resolve on Python 3.14, even though
the base viewer can. This was checked against PyPI on 2026-09-12.

| Extra | Hook dependency installed | Scope |
| --- | --- | --- |
| `crewai` | `crewai>=0.100` | CrewAI event hooks |
| `langgraph` | `langchain-core>=0.3` | LangChain callbacks; install `langgraph` and your provider separately if needed |
| `autogen` | `autogen-core>=0.4` | AutoGen 0.4+ client interface, not legacy `pyautogen`; install `autogen-agentchat` and provider extras separately |
| `openai-agents` | `openai-agents>=0.1` | OpenAI Agents SDK tracing |
| `tiktoken` | `tiktoken>=0.7` | Optional tokenizer for local text estimates |
| `otel` | OTel SDK + OTLP/HTTP exporter | Optional configured span export |

`all` combines the framework hook dependencies and `tiktoken`, not `otel`,
full LangGraph/AutoGen applications, or every provider. Prefer the extra
you need; installing `all` may change dependencies in your agent environment.
`doctor` checks discoverable SDK versions, not end-to-end compatibility;
verify a small real run and inspect its trace before trusting totals.

![Live Auditor dashboard, screenshot of a real crewAI session](https://raw.githubusercontent.com/surajJha/contextOS-auditor/main/docs/screenshots/live-dashboard.png)

*A real `watch --serve` screenshot from a live CrewAI run — actual token
counts, estimated $ cost, and detected waste tokens, not a mockup.*

### "I don't have a Python env set up"

If you're attaching this to your own agent: CrewAI/LangGraph/AutoGen/
OpenAI Agents SDK are all Python-native frameworks, so if your agent runs
at all, you already have a working Python + pip — that's how you installed
the framework itself. The `attach()`/callback-handler snippet has to be
`pip install`ed into that *same* interpreter no matter what, since it hooks
the framework's own event bus from inside your process.

If installation fails with an `externally-managed-environment` error
(common on recent macOS/Debian system Pythons), activate your agent's
virtual environment first. For a new project, create one as above.
With an existing uv-managed project:

```bash
uv add contextos-auditor
uv run contextos-auditor doctor
```

For uv without a project, run `uv venv` before `uv pip install contextos-auditor`,
then activate that environment or use `uv run`. Do not bypass system
Python protections.

If you only want to **view** a teammate's session or try the demo, pipx is
appropriate:

```bash
pipx install contextos-auditor
contextos-auditor demo --serve
```

**pipx does not install the adapter into your agent's environment.** Install
there separately to import `contextos_auditor` from your agent.

There are currently **no published standalone binaries** on
[GitHub Releases](https://github.com/surajJha/contextOS-auditor/releases).
Use the Python CLI, or ask the person recording a session to export a
self-contained HTML report that you can open without Python.
`scripts/build_binary.sh` is a local macOS/Linux viewer build helper, not
a prebuilt download or a Windows build guarantee.

## Quickstart

```python
# crewai
from contextos_auditor.crewai import attach
audit = attach(task="fix the bug")
crew.kickoff()
audit.detach()
```

```python
# langgraph / any langchain_core-based agent
from contextos_auditor.langgraph import AuditorCallback
handler = AuditorCallback(task="fix the bug")
graph.invoke({"messages": [...]}, config={"callbacks": [handler]})
handler.finish()
```

```python
# openai agents sdk
from contextos_auditor.openai_agents import attach
audit = attach(task="fix the bug", model_hint="gpt-4o-mini")  # use your actual model
result = await Runner.run(agent, "do the thing")
audit.detach()
```

OpenAI Agents auditing requires SDK tracing to remain enabled; disabling
tracing also disables these observations. Setting
`trace_include_sensitive_data=False` can remove tool inputs/outputs and
model details, reducing observability. `model_hint` supplies a known model
name for pricing; it cannot restore missing tool observations.
The SDK's own tracing/export configuration is separate from Auditor OTel.

```python
# autogen
from contextos_auditor.autogen import new_session, wrap_client, audit_tool
session = new_session(task="fix the bug", model="gpt-4o-mini")  # use your actual model
client = wrap_client(real_client, session)
agent = AssistantAgent("coder", model_client=client, tools=[audit_tool(write_file, session)])
...
session.finish()
```

For AutoGen, specify the exact model when known: a client's model family
may not identify the billable model. Client wrapping captures model usage;
wrap each tool with `audit_tool` to capture its arguments and results.

Then, from a terminal, while (or after) your agent runs:

```bash
contextos-auditor watch              # live terminal table, auto-picks the
                                       # most recent session
contextos-auditor watch --serve       # localhost-only live view in a browser
                                       # tab (Server-Sent Events, no polling)
contextos-auditor report <id> --html out.html   # one-shot static HTML report
contextos-auditor doctor              # check which framework hooks are
                                       # available in this environment
```

Run the viewer from the agent's working directory, or pass
`--audit-root /path/to/project/.contextos/audit` after the subcommand.
Otherwise it may find no sessions or show a different project's run.
Use `try`/`finally` to call `detach()` or `finish()` if your agent can fail.
Create a fresh attachment/session for each run; do not reuse a detached
attachment or finished session.

### Concurrent runs

CrewAI and OpenAI Agents adapters use process-global hooks. Keep **one
active audit scope/run per process**: overlapping independent runs can
mix observed events, even when their session IDs differ. Use separate
worker processes for concurrent user requests that need isolated audits.
Async and streaming execution within a single run do not provide
cross-run isolation.

LangGraph records through the callback handler supplied to a run;
AutoGen records through the wrapped client/tools and their session.
Keep those handlers, wrappers, and sessions separate for independent
runs rather than sharing a finished or concurrently reused audit scope.

### Windows, containers, SSH, and CI

On Windows, create the environment with `py -m venv .venv`. If PowerShell
activation is blocked, no policy change is needed: use
`.\.venv\Scripts\python.exe -m pip install contextos-auditor` and
`.\.venv\Scripts\contextos-auditor.exe doctor` directly.
The Bash binary-build helper is not a native Windows installer.

For a headless machine or CI, skip `--serve` and write a portable report:

```bash
contextos-auditor demo --html demo.html
contextos-auditor report --audit-root .contextos/audit --html report.html
```

Treat report files and session directories as sensitive before sharing.
For Docker, install the adapter in the image's agent environment and persist
the audit directory in a volume. Open exported HTML or run the viewer on
the host against that mounted directory. `watch --serve` binds to
`127.0.0.1` inside the container; `docker -p` alone does not expose it.
For an SSH host, forward its loopback port
(`ssh -L 8765:127.0.0.1:8765 user@host`) and open
`http://127.0.0.1:8765/` locally while the remote viewer runs.

Not sure any of this is working? Run `contextos-auditor doctor` first —
it tells you exactly which framework SDKs it can see and prints the
correct snippet for each, before you touch your agent code at all.

## Reading the trace

Both the terminal output and the dashboard now show a nested **turn →
tool call** trace under the summary totals (AUD-013) — not just the
bottom-line numbers. Each turn lists the tools called during it, and any
write that would have been smaller with a hunk-based edit is called out
inline, on the exact turn it happened, in red:

```
turn 6: 689 tokens (prompt=613 completion=76)
  +-- write_file
      L waste detected: write to config/service.yaml could have been
        29 tokens smaller with a hunk-based edit
```

## Viewing past sessions

Every run is written to its own directory under `--audit-root`
(`.contextos/audit` by default) and never overwritten or pruned. To see
every recorded session at a glance — not just the most recent one that
`watch`/`report` show by default — run:

```bash
contextos-auditor history                # newest 20 sessions
contextos-auditor history --limit 0      # every session, no cap
contextos-auditor history --limit 5      # newest 5
```

This reads only the `session.json`/JSONL files each session already
writes — no separate database, no aggregation step to keep in sync.

Add `--html` to also write the same history as a self-contained page with
sparklines for tokens, cost and estimated savings across runs — a trend is
the one thing a fixed-width terminal table is genuinely bad at showing:

```bash
contextos-auditor history --html history.html
```

The page has no scripts, no network requests and no build step, so it can
be opened from disk or attached to a PR. It carries exactly the same
caveats as the terminal view: any session that could not be read is named
rather than quietly dropped, a run with unreadable lines is flagged on its
own row, and a session whose model has no published price shows `n/a`
rather than being plotted as a free run.

## What it actually measures

Observed model usage is pulled from the framework's own usage
reporting (CrewAI's `LLMCallCompletedEvent.usage`, LangChain's
`AIMessage.usage_metadata`, the OpenAI Agents SDK's tracing spans,
AutoGen's `ChatCompletionClient.create()` return value), when exposed by
the SDK. Missing events or usage can leave totals incomplete; a zero is
not proof of a free run. Local tool-text token estimates use a characters/4
heuristic unless the optional tokenizer is available; even tokenizer counts
are not a reconstruction of a provider's complete prompt. The "savings if Kit were attached"
figure is a **local, offline estimate** computed from your own recorded
tool calls — it does not change your bill, and it is clearly labeled
`estimated` everywhere it appears, never presented as a measured result.

Two kinds of waste are counted, and both are shown with the arithmetic
that produced them, so you can check the headline rather than trust it:

1. **Whole-file rewrites.** Your agent sent an entire file to change a
   few lines. The waste is the size of the full write minus the size of
   the equivalent hunk-based edit.
2. **Duplicate context.** Your agent re-read content it was already
   carrying in the transcript. That content is billed again in the prompt
   of *every* turn that follows it, so the waste is its size multiplied
   by the number of turns it was carried through. In long ReAct loops
   this is usually the larger of the two.

The duplicate-context figure is an **upper bound** on providers that bill
repeated prompt prefixes at a cached-token discount — the trace doesn't
tell us whether caching was active for your run. The total is also
clamped to the prompt tokens the session actually spent, so the estimate
can never claim more waste than the run demonstrably paid for.

**$ cost** is shown alongside token counts when your session's model is
in a small, hand-curated, dated pricing snapshot
(`contextos_auditor/_internal/pricing.py`), sourced from
[litellm's publicly maintained pricing table](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json).
This is a **list-price estimate, not your actual bill**: providers change
prices without notice, this snapshot will go stale, and volume
discounts/enterprise agreements/cached-token pricing are not modeled. If
your model isn't in the table, the Auditor shows "no dated pricing
available" — it never guesses or interpolates a number.

## Exporting to your existing observability stack (optional)

By default, the Auditor only ever writes to a local JSONL/JSON directory
on your disk — nothing else. If your team already runs an OTel collector
(Datadog, Grafana, Honeycomb, Jaeger, ...), you can *additionally* export
each turn as a real OTel span following the
[OTel GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/)
(`gen_ai.system`, `gen_ai.request.model`, `gen_ai.usage.input_tokens`, ...):

```bash
python -m pip install "contextos-auditor[otel]"
```

```python
audit = attach(task="...", otel_endpoint="http://localhost:4318/v1/traces")
# or, with zero code changes:
# CONTEXTOS_OTEL_ENDPOINT=http://localhost:4318/v1/traces python your_agent.py
```

This is strictly additive and opt-in: nothing is exported unless you set
one of the two above, the local JSONL trail is completely unaffected
either way. Missing optional packages disable export with a warning.
An unreachable collector can produce exporter errors or dropped spans;
local recording remains independent.

## Secret redaction (on by default)

Pattern-based secret redaction is **on by default**. Recognizable secret
*shapes* (AWS keys, OpenAI/GitHub/Slack-style tokens, JWTs, PEM private
keys, and generic credential assignments) are replaced with `[REDACTED]`
before anything is written to disk. Only the matched value is replaced --
**not** the whole tool call -- so the real file content that powers
write-waste detection is left intact.

It defaults on because the two failure modes aren't symmetric: a
credential written into a plaintext file (and possibly committed) can't be
un-written, whereas the cost of redaction being on is only that a
credential-shaped string reads as `[REDACTED]` in the trace view.

If you need the raw values -- e.g. you're debugging the auditor itself, on
data you know is safe:

```python
audit = attach(task="...", redact_secrets=False)
# or: CONTEXTOS_REDACT_SECRETS=0 python your_agent.py
```

This is a best-effort scrub for common secret patterns, not a guarantee
that no sensitive data of any kind is ever recorded -- if you need that
guarantee, don't pass secrets through tool args/results in the first
place.

## Privacy

Session data (`events.jsonl`/`session.json`) is written to a directory on
your own disk (`./.contextos/audit/<session-id>/` by default).
By default, the Auditor does not upload these recordings. If you set
`otel_endpoint` or `CONTEXTOS_OTEL_ENDPOINT`, it additionally sends model
and tool span metadata (including model/tool names, usage and estimated
cost) to that endpoint. Your agent/framework may have its own network
traffic or tracing, independently of the Auditor. On the first `attach()` in a
process the auditor prints the exact path it is writing to and whether
redaction is on, so this is never a surprise (set `CONTEXTOS_QUIET=1` to
silence it in CI). `contextos-auditor watch --serve` binds a small local
HTTP server to `127.0.0.1` only. It has no authentication: keep it on
loopback and do not expose it through a public proxy or tunnel.
Offline default-path checks live in `tests/test_no_network_calls.py`;
they are not a promise that an agent process or opt-in export never uses
the network.

Tool calls are recorded with their real arguments and results (e.g. file
paths and contents your agent read/wrote) so the savings estimate can be
computed — this can include whatever your own agent's tools touch. Add
`.contextos/` to your project's `.gitignore` so session data never gets
committed alongside your code:

```
echo ".contextos/" >> .gitignore
```

## Where this comes from

This package is the canonical, standalone Auditor implementation. The
monorepo's `dashboard/adapters/`, `dashboard/audit_emit.py` and
`dashboard/shadow_kit.py` are compatibility facades over this package, not
separate copies. They retain their legacy names and `out/audit` default
directory while sharing normalization, default-on secret redaction, model
backfill, synthetic tool flushes and bounded estimates.

The package has no dependency on the monorepo, Kit, or spike code. In a
repository checkout, `dashboard/__init__.py` makes this sibling package
importable so legacy scripts work without an editable install, including
with `python -S`. To use the public package directly during development,
install it from the repository root with
`python -m pip install -e packages/contextos-auditor-py --no-deps`.

Session rendering remains public through `contextos_auditor.report`; the
page template and history renderer live in separate internal modules.
Shadow file observations and billed-usage accounting are likewise separate.
All waste rows share the headline's spend ceiling; duplicate carry counts
exclude unrecorded turns and terminal-only tool flushes.

## Development

```bash
pip install -e ".[dev,all]"
pytest tests/
```

## License

**Free for any use, including commercial.** Licensed under
[PolyForm Shield 1.0.0](https://polyformproject.org/licenses/shield/1.0.0) —
see [`LICENSE`](https://github.com/surajJha/contextOS-auditor/blob/main/LICENSE). Run it on your company's agents, inspect it,
fork it, modify it, ship it inside your product — no fee, no signup, no
commercial license to buy. The single restriction is **Noncompete**: you
may not use it to provide a product that competes with ContextOS. It is
source-available rather than OSI open source for exactly that reason, and
we'd rather say so plainly than blur the term.
