Watchlight — Developer Edition
Govern an AI agent in five minutes. One install, zero infrastructure, same API as production.
Watchlight puts a policy decision point in front of every action your agents take. It authorizes each tool call and records a value-free audit trail.
The Developer Edition runs the real authorization engine in-process. No
server, no database, no signup — a governed ALLOW / DENY on your laptop, in
the same code you ship to production.
pip install watchlight # Python 3.9+, prebuilt wheels
npm install @watchlight/sdk # Node 18+, the compiled engine comes with it
Quickstart
Python — save as agent.py, run python agent.py:
from watchlight import govern, configure_default, Denied
configure_default(agent="research-agent") # the name on every record
# Permit ONLY "research". Fail-closed: everything else is denied.
govern.allow('permit(principal, action == Action::"research", resource);')
@govern.tool(intent="research")
def web_search(query: str) -> str:
return f"results for: {query}"
@govern.tool(intent="transfer") # governed, but no policy permits it
def transfer_funds(to: str, amount: int) -> str:
return f"sent ${amount} to {to}" # never runs — denied first
print(web_search("watchlight docs")) # ALLOW → the body runs
try:
transfer_funds("mallory", 1000) # DENY → refused before the body runs
except Denied as e:
print(e)
TypeScript / Node — the same program ("type": "module" or a .mjs file):
import { govern, configureDefault, Denied } from "@watchlight/sdk";
configureDefault({ agent: "research-agent" });
govern.allow('permit(principal, action == Action::"research", resource);');
async function webSearch(query: string) { return `results for: ${query}`; }
async function transferFunds(to: string, amount: number) { return `sent $${amount} to ${to}`; }
const search = govern.tool(webSearch, { intent: "research" });
const transfer = govern.tool(transferFunds, { intent: "transfer" }); // nothing permits it
console.log(await search("watchlight docs")); // ALLOW → the body runs
try {
await transfer("mallory", 1000); // DENY → refused before the body runs
} catch (e) {
if (e instanceof Denied) console.log(e.message);
}
Both lanes print the same decisions:
watchlight: governing 'research-agent' (dev mode, in-process engine)
watchlight: ALLOW research tool/web_search
results for: watchlight docs
watchlight: DENY transfer tool/transfer_funds not authorized
watchlight denied intent 'transfer' on tool/transfer_funds: not authorized
Node names the same tools tool/webSearch and tool/transferFunds. Both also
print a one-time note that no audit sink is configured.
That DENY is the product. The transfer_funds body never ran, and the
decision is already on disk in .watchlight/audit.jsonl.
What you can govern
Python — pip install … |
Node — npm install … |
|
|---|---|---|
| A tool you wrote | watchlight → @govern.tool(intent=…) |
@watchlight/sdk → govern.tool(fn, { intent }) |
| A framework agent | watchlight[langgraph] · [pydantic-ai] · [claude-agent] · [deepagents] |
governedHooks() for the Claude Agent SDK, governTool() for LangChain / LangGraph.js |
| An MCP server | watchlight-mcp — a policy enforcement point in front of any MCP server |
point any MCP client at that same PEP |
| Your own app | govern.authorize(…); watchlight-agent-sdk adds sessions, preflight and local lineage (it imports as watchlight_core) |
await govern.authorize({…}) |
pip install "watchlight[all]" is one install for the whole Python lane, and
every Python example in the documentation runs after it. On the Node lane
@watchlight/sdk is the only install you need.
Both lanes write .watchlight/audit.jsonl, and watchlight dev tails it:
watchlight dev # → http://localhost:7000
Who is acting, and on whose behalf
A governed call answers two separate questions.
// this runtime may book for any user — whoever it acts for
permit(principal is User, action == Action::"book", resource)
when { context.actor == "flight-booker" };
| Question | Where it goes |
|---|---|
| On whose behalf does this run? | principal — the subject, e.g. User::"db:4412" |
| Which runtime is acting? | context.actor, set by the SDK from the agent name |
| Through whose delegation? | context.actor_chain |
| Under what narrowed authority? | govern.scope(tools=[...]) |
That is what separates a policy from an if: it names whichever runtime is
acting and whoever it acts for. The SDK sets context.actor itself and
refuses a caller-supplied value that disagrees, so a policy can trust it.
Where to go next
→ The documentation index — every page, and when to read it.
Runnable programs live in examples/ — start with
governed_research_agent.py or
ts/examples/agent.mjs. Copy-paste policy recipes for
the high-stakes decisions — spending money, deleting things, messaging the
outside world, stopping a runaway agent — are in
examples/patterns/, each one run through the real engine.
A note on identity
The Developer Edition authorizes the principal you assert — the agent you
construct the governor with, or the Watchlight-Agent-Id on a governed MCP
request. It does not cryptographically prove the caller. On your own machine,
running both sides, that is the right trade.
Bind any non-loopback listener behind something that authenticates the caller — a reverse proxy doing mTLS or OIDC, or the Enterprise plane.
Identity hardens as you grow, without changing your policies:
- Developer Edition — the principal is asserted (cooperative, local dev).
- Next — an optional signed session token binds the principal to a key your process holds, so a prompt-injected sub-agent cannot rewrite a header to escalate. It still needs no external infrastructure.
- Enterprise — identity is attested: federated (OIDC) and workload (mTLS), verified across the fleet.
Only how strongly the principal is proven changes. The policies do not.
Developer Edition vs Enterprise
Enterprise points the same code at a running control plane — no rewrite. What changes is what happens around the decision.
What the Developer Edition does, and Enterprise keeps
| Capability | Developer Edition | Enterprise |
|---|---|---|
| Allow / require approval / deny, on real Cedar | ✅ in-process engine, policies from a local file | ✅ a running, scaled decision service |
| Strict-subset sub-agent attenuation | ✅ engine-side, to a depth of 5 | ✅ server-side, depth configurable per agent above a tenant default |
| Human-in-the-loop approvals | ✅ single-use tokens | ✅ across the fleet, with an operator queue |
| Content screening | ✅ rule-based and in-process: govern.sanitize, govern.screen |
✅ the same class of check as a managed service — centrally authored policies, applied to traffic your code never touches |
| Framework plugins | ✅ LangGraph, Pydantic AI, Claude Agent SDK, DeepAgents, LangChain.js, MCP | ✅ those plus Claude Code, Google ADK, AWS Bedrock, Microsoft Agent Framework, OpenClaw |
| Scopes across a process boundary | ✅ HMAC scope token — integrity within one trust domain | ✅ independently attestable scopes |
| Dashboard | ✅ watchlight dev → localhost:7000 |
✅ the operator console |
What only Enterprise does
| Capability | Developer Edition | Enterprise |
|---|---|---|
| Real-time enforcement effects — quarantine an agent, terminate a run, sever a delegation subtree, revoke authority | ❌ the policy loads and the call is denied; the containment action never fires | ✅ a contained agent's live connections are force-closed mid-run, server-side, with no cooperation from the agent; a sever durably collapses the delegation tree |
| Drift detection | ❌ | ✅ an agent leaving its declared plan is quarantined automatically, and its live connections drop |
| Runtime enforcement proxy | ❌ governs in-process, plus a PEP in front of one MCP server | ✅ agent egress is mediated on the wire as well as in-process, so a call has to clear both |
| Discovery and registry | ❌ | ✅ continuously scans your environments for agents and MCP servers, and tracks trust state |
| Signed execution lineage | ❌ local JSONL, unsigned | ✅ each step is signed, persisted and verified fail-closed, over a hash-chained audit trail anyone can re-verify |
| Fleet-wide revocation | ❌ one process | ✅ revocation is durable and enforced at the credential broker, across tenants |
| Attested identity | ❌ the principal is asserted | ✅ OIDC federation and mTLS workload identity |
| Air-gapped fleet deployment | ❌ the library itself runs offline, but there is no plane to deploy | ✅ on-premises, with local policy evaluation |
Everything the Developer Edition leaves out needs state outside your process — a fleet to revoke across, a plane to quarantine into, a key to sign lineage with. What it keeps is every guarantee that fits in one process: fail-closed semantics, engine-side attenuation, explicit scopes, and value-free audit are identical in both.
→ The platform · email sales@watchlight.ai
Open source, and the license
Everything you write against is open and Apache-2.0 — the govern decorator
and scope attenuation, the CLI and the watchlight dev dashboard, the framework
plugins, the MCP PEP's transport layer, and every example here.
You do not have to trust a black box to trust the decisions. Policies are
standard Cedar — open, formally specified, and
deterministic. The integration layer is readable, so you can see exactly what
the engine is asked and what it returns. And every ALLOW / DENY lands
value-free in a file you can grep.
The decision engine ships as a compiled wheel — watchlight-engine and the
watchlight-mcp runtime — under the Watchlight Developer Edition license. Both
are free to use, including in production and commercially, for up to 25
governed agents per organization. A commercial license is needed only above
that, or to re-offer the engine itself as a hosted authorization service.
Want the engine source, an air-gapped build, or to govern a fleet in production? email sales@watchlight.ai.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file watchlight-0.10.0.tar.gz.
File metadata
- Download URL: watchlight-0.10.0.tar.gz
- Upload date:
- Size: 193.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28a024741c30f2bae4f5d5d53700250e7029a4a2b4f96405076ff175f492ca47
|
|
| MD5 |
920126be9f2a02dd0e91878cee2ac7c0
|
|
| BLAKE2b-256 |
d29b2300aafb42ffab43c893d5e386c716db1414b1f0e999318d75ac740985c7
|
Provenance
The following attestation bundles were made for watchlight-0.10.0.tar.gz:
Publisher:
publish.yml on watchlight-ai-beacon/watchlight-de
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
watchlight-0.10.0.tar.gz -
Subject digest:
28a024741c30f2bae4f5d5d53700250e7029a4a2b4f96405076ff175f492ca47 - Sigstore transparency entry: 2751240565
- Sigstore integration time:
-
Permalink:
watchlight-ai-beacon/watchlight-de@528f334bedd546f1c3c82d1b85940a33713fa098 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/watchlight-ai-beacon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@528f334bedd546f1c3c82d1b85940a33713fa098 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file watchlight-0.10.0-py3-none-any.whl.
File metadata
- Download URL: watchlight-0.10.0-py3-none-any.whl
- Upload date:
- Size: 129.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c46578102e5fbaf99fdab68b2fccfcdbaa33ecac8578a4aa384efdb40b50b549
|
|
| MD5 |
177885333b7cf78955e033e0358d23da
|
|
| BLAKE2b-256 |
d1cb34845a089b5dbc78fd8117d3acabd375c9fcbfe7214315fd016413be8c8b
|
Provenance
The following attestation bundles were made for watchlight-0.10.0-py3-none-any.whl:
Publisher:
publish.yml on watchlight-ai-beacon/watchlight-de
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
watchlight-0.10.0-py3-none-any.whl -
Subject digest:
c46578102e5fbaf99fdab68b2fccfcdbaa33ecac8578a4aa384efdb40b50b549 - Sigstore transparency entry: 2751241229
- Sigstore integration time:
-
Permalink:
watchlight-ai-beacon/watchlight-de@528f334bedd546f1c3c82d1b85940a33713fa098 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/watchlight-ai-beacon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@528f334bedd546f1c3c82d1b85940a33713fa098 -
Trigger Event:
workflow_dispatch
-
Statement type: