watchlight-core
Shared HTTP client and governance primitives used by every Watchlight
AI framework plugin (watchlight-adk, watchlight-langgraph,
watchlight-bedrock, …).
Why this exists
Until #312, the same APDP HTTP client lived as three near-identical copies under each framework plugin. As the contract stabilised across ADK / LangGraph / Bedrock, three copies became the right trigger for extraction. This package is the single source of truth for:
- The HTTP wire format with WL-APDP (
ApdpClient) - Plan-validation / preflight result wrappers (
PlanResult,PreflightResult) - The plan-normalisation contract (
normalize_plan) - The framework-agnostic
GovernanceStateshape consumed by the Beacon Dashboard / Streamlit governance card - The base run-handle lifecycle (
BaseRunHandle) - Shared error types and the
governance_modeenv reader - Plugin telemetry contract (
GovernanceTelemetry)
What's intentionally NOT here
Framework-specific behaviour stays in the plugin packages:
- ADK lifecycle callbacks +
PlanReActPlannerparser +BaseToolset—watchlight-adk - LangGraph plan-and-execute primitives —
watchlight-langgraph - AWS Bedrock event parsing + Lambda action-group decorator +
bedrock_session_attributes()helper —watchlight-bedrock
Install
# Minimal — APDP client + governance primitives only
pip install watchlight-core
# With OpenTelemetry export support (adds ~50MB of OTel SDK deps)
pip install 'watchlight-core[otlp]'
# Or in this monorepo:
pip install -e plugins/watchlight-core
pip install -e 'plugins/watchlight-core[otlp]'
Plugins depend on it explicitly via their pyproject.toml; the core
package depends only on httpx and (on Python 3.10) typing-extensions.
The [otlp] extra pulls in opentelemetry-api, opentelemetry-sdk, and
opentelemetry-exporter-otlp-proto-http — optional so cold-start-
sensitive environments (Lambda, Cloudflare Workers) don't pay the install
weight when they're not exporting to OTel.
Public API
from watchlight_core import (
# HTTP client
ApdpClient,
# Errors
WatchlightError,
AgentNotRegistered,
GovernanceUnavailable,
# Result wrappers
PlanResult,
PreflightResult,
# Plan / state
normalize_plan,
GovernanceState,
GovernanceTelemetry,
state_from_attrs,
# Lifecycle
BaseRunHandle,
GovernedPlugin,
# Custom-agent SDK (EN.6)
watchlight,
# OpenTelemetry export (EN.6) — requires [otlp] extra at construction
OtlpConfig,
OtlpProfile,
WatchlightOtlpExporter,
# Env
governance_mode,
)
Custom-agent SDK (@watchlight)
For agents NOT built on a framework with a Watchlight plugin (LangGraph,
ADK, Bedrock), the @watchlight decorator emits the canonical lineage
events for any Python function:
from watchlight_core import ApdpClient, watchlight
client = ApdpClient(base_url="http://localhost:8081")
@watchlight(agent_id="custom-research", apdp_client=client)
async def run_research(query: str) -> str:
# Your agent logic — emits execution_started / completed / failed
return result
OpenTelemetry export
Opt-in customer observability — sends a deliberate subset of the
lineage stream to your OTel collector. Default is profile=off; the
exporter is a no-op until you turn it on.
from watchlight_core import OtlpConfig, WatchlightOtlpExporter
# Profile ladder: off ⊂ metrics ⊂ standard ⊂ governance
otlp = WatchlightOtlpExporter(OtlpConfig.from_env())
# WL_OTLP_PROFILE=standard
# WL_OTLP_ENDPOINT=http://otel-collector:4318
Tool arguments, LLM prompts, ABR raw scores, drift baselines, and
security-internal anomalies never leave Watchlight. The exported subset
is documented in dev-docs/architecture/otlp-export.md.
The package exposes a py.typed marker so type checkers (mypy, pyright)
pick up the inline annotations directly.
Contract stability
Anything in watchlight_core/__init__.py's __all__ is a stable
public API under SemVer minor-version compatibility. Anything else
is internal and may move between minor versions.
When changing the wire format with WL-APDP (e.g. adding a route or
field), update ApdpClient here — the plugins inherit it for free.
Building a new plugin
Implement the framework integration surface (lifecycle hooks, native plan format, etc.) in your plugin package and use this package for everything else:
- Inherit
GovernanceTelemetryto satisfy thelast_*contract. - For frameworks with explicit primitives (LangGraph, Bedrock):
subclass
BaseRunHandleand add framework-specific helpers; exposestart_run(slug)returning your subclass. - For frameworks with lifecycle callbacks (ADK): use
ApdpClientdirectly and populate thelast_*attributes from your callbacks. - Provide a one-line
state_from_<framework>_pluginstate helper usingstate_from_attrs(plugin, framework="<name>").
The GovernanceState shape parity test in your plugin's test suite
guarantees the dashboard renders consistently across frameworks.
Cross-references
- Multi-framework contract:
dev-docs/architecture/proxy-plugin-interop.md§6 - Threat model:
dev-docs/security/HARDENING.md(entries #301, #312, plus this PR's entry)
Open-source by design — the plugin is glue
This package (and the framework plugins built on it) ships as readable,
Apache-2.0 source. That's safe because all authorization decisions, scope
strict-subset attenuation, lineage/audit signing, and drift/anomaly scoring are
server-side — in the compiled Rust core (wl-apdp) and the governed platform.
The plugin registers hooks, shapes a request, round-trips it to the PDP, and
projects the answer.
There is no differentiating IP to strip for a community build: the difference between Developer Edition and Enterprise is the backend the plugin talks to (the in-process DE engine vs. the full governed plane), never the plugin code. And because any decision made client-side is bypassable, keeping enforcement server-side is a security rule, not just an IP one.
This boundary is documented in plugins/CONTRIBUTING.md
and enforced in CI by the plugin IP-boundary gate
(scripts/ci/check_plugin_ip_boundary.py).
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_agent_sdk-0.5.0.tar.gz.
File metadata
- Download URL: watchlight_agent_sdk-0.5.0.tar.gz
- Upload date:
- Size: 322.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65a919ccef9c724dc48e9f69233b220f0d6c12aad8c43db863ee3f8881ed89f5
|
|
| MD5 |
97cc8d96543f64ab1cfa0a6f7ec73391
|
|
| BLAKE2b-256 |
48eb9bea95b8a596f387a8b5ae0fa05b6924d0944a81444e0aac9a63999223f0
|
Provenance
The following attestation bundles were made for watchlight_agent_sdk-0.5.0.tar.gz:
Publisher:
publish-python-sdk-plugins.yml on watchlight-ai-beacon/watchlight-beacon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
watchlight_agent_sdk-0.5.0.tar.gz -
Subject digest:
65a919ccef9c724dc48e9f69233b220f0d6c12aad8c43db863ee3f8881ed89f5 - Sigstore transparency entry: 2500027053
- Sigstore integration time:
-
Permalink:
watchlight-ai-beacon/watchlight-beacon@79d796d2d14063177965847fdfdb49b830d2d22e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/watchlight-ai-beacon
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-sdk-plugins.yml@79d796d2d14063177965847fdfdb49b830d2d22e -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file watchlight_agent_sdk-0.5.0-py3-none-any.whl.
File metadata
- Download URL: watchlight_agent_sdk-0.5.0-py3-none-any.whl
- Upload date:
- Size: 202.5 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 |
e2981ce91cc676a9dc52c3e70be26eff55776654e4c059fc1ed544ba206c747b
|
|
| MD5 |
abc628c084c1b74fe22006bad42d9b13
|
|
| BLAKE2b-256 |
238c3a800725c99a80f4dcd64bc0dcd22f2d9c9d187d4e03a3b210de58ed8fd7
|
Provenance
The following attestation bundles were made for watchlight_agent_sdk-0.5.0-py3-none-any.whl:
Publisher:
publish-python-sdk-plugins.yml on watchlight-ai-beacon/watchlight-beacon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
watchlight_agent_sdk-0.5.0-py3-none-any.whl -
Subject digest:
e2981ce91cc676a9dc52c3e70be26eff55776654e4c059fc1ed544ba206c747b - Sigstore transparency entry: 2500027070
- Sigstore integration time:
-
Permalink:
watchlight-ai-beacon/watchlight-beacon@79d796d2d14063177965847fdfdb49b830d2d22e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/watchlight-ai-beacon
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-sdk-plugins.yml@79d796d2d14063177965847fdfdb49b830d2d22e -
Trigger Event:
workflow_dispatch
-
Statement type: