Skip to content
Merged
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
65 changes: 40 additions & 25 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,34 @@ practice, the package covers both supervision and governance.

### Current Roadmap Focus

The current build focus is the v0.1 runtime: LangGraph adapter first, then the
deterministic policy/risk Decision Gate. Work in this repo should reinforce
that sequencing rather than jumping ahead to later judge- or multi-framework
features.
v0.1 (Sidecar runtime, LangGraph adapter, deterministic policy/risk Decision
Gate, Observe mode) and v0.2 (Intent Guardian, Govern mode) have shipped.
The current build focus is v0.2.x, the narrow Early Validation Benchmark
(see ROADMAP.md). Work in this repo should reinforce that sequencing rather
than jumping ahead to Planner/Critic/Judge (v0.3) or multi-framework
features (v0.6).

### Before You Build Here

- Ask whether the feature is a pre-action governance concern; if it is
retrospective analysis, it likely belongs in `agenticlens` instead
- Keep v0.1 deterministic where the roadmap says it should be deterministic;
do not solve early gate behavior with model-based evaluators
- Keep the Decision Gate deterministic where the roadmap says it should be
(`gate/`, `intent/`); do not solve that behavior with model-based
evaluators
- Avoid designing sidecar abstractions as if all frameworks are already
supported; the first real adapter is still shaping the boundary

## Status

This repository is a **scaffold** — directory layout, tooling config, and
CI/release workflows exist; `src/agentic_sidecar/` modules are placeholders
(docstring only, `NotImplementedError` on any callable if one exists) until
their version lands. See [ROADMAP.md](ROADMAP.md) for the build order before
adding real logic to any module.
v0.1 and v0.2 are implemented: `core/` (`Sidecar`, `Decision`,
`DecisionContext`, `operators.py`, `exceptions.py`), `gate/policy.py`,
`gate/risk.py`, `intent/` (`IntentEnvelope`, `IntentGuardian`,
`ConstraintBinding`), and `adapters/langgraph.py` (both Observe and Govern
mode) have real code and tests. Everything else under
`src/agentic_sidecar/` (`evaluators/`, `status/`, `cli/`, `gate/budget.py`,
the remaining `adapters/*.py`, `integrations/*.py`) is still a placeholder
(docstring only) until its version lands. See [ROADMAP.md](ROADMAP.md) for
the build order before adding real logic to any of those.

## Build and Run

Expand All @@ -88,15 +95,16 @@ adding real logic to any module.
## Design Constraints

These are load-bearing, not preferences — see
[ROADMAP.md § Design Constraints](ROADMAP.md#design-constraints-read-before-building-v01)
[ROADMAP.md § Design Constraints](ROADMAP.md#design-constraints-read-before-building-v01v02)
for the full rationale on each:

1. **One framework adapter first.** `adapters/langgraph.py` before any of
the other four. Do not claim framework independence until a second
adapter has been built against real usage.
2. **Rules before models.** v0.1's `gate/policy.py` and `gate/risk.py` must
work with zero LLM calls. Don't reach for `evaluators/judge.py` (v0.3)
to solve a v0.1 problem.
2. **Rules before models.** `gate/policy.py`, `gate/risk.py`, and (v0.2)
`intent/alignment.py` must all work with zero LLM calls. Don't reach for
`evaluators/judge.py` (v0.3) to solve a problem these can answer
deterministically.
3. **`on_sidecar_failure` has no default.** Every Decision Gate path must
handle `fail_open` and `fail_closed` explicitly — this is a governance
property, not an implementation detail.
Expand All @@ -111,18 +119,18 @@ for the full rationale on each:

## Repo Map

| Path | Purpose | Planned version |
| Path | Purpose | Version |
|------|---------|------------------|
| `src/agentic_sidecar/core/` | `Sidecar` class, `attach()`, decision-boundary interception, `Decision` type | v0.1 |
| `src/agentic_sidecar/gate/policy.py` | Policy Advisor — deterministic YAML allow/deny rules | v0.1 |
| `src/agentic_sidecar/gate/risk.py` | Risk Evaluator — rule-based classification | v0.1 |
| `src/agentic_sidecar/core/` | `Sidecar` class (`evaluate()`, `before_tool_call` hook), `Decision` type, `DecisionContext`. `attach()` is *not* here — see AGENTS.md's Package Boundaries, adapters own it | v0.1 (implemented) |
| `src/agentic_sidecar/gate/policy.py` | Policy Advisor — deterministic YAML allow/deny rules | v0.1 (implemented) |
| `src/agentic_sidecar/gate/risk.py` | Risk Evaluator — rule-based classification | v0.1 (implemented) |
| `src/agentic_sidecar/gate/budget.py` | Budget Guardian — cost/token ceilings | v0.4 |
| `src/agentic_sidecar/adapters/langgraph.py` | LangGraph interception adapter | v0.1 |
| `src/agentic_sidecar/intent/` | `IntentEnvelope`, alignment scoring, drift detection | v0.2 |
| `src/agentic_sidecar/adapters/langgraph.py` | LangGraph interception adapter, incl. `attach(sidecar, tools)`; enforces `BLOCK` in Govern mode (v0.2) | v0.1/v0.2 (implemented) |
| `src/agentic_sidecar/intent/` | `IntentEnvelope`, `IntentGuardian`, `ConstraintBinding` — constraint validation only, no `authority` enforcement yet | v0.2 (implemented) |
| `src/agentic_sidecar/evaluators/planner.py` | Planner — evaluates the whole plan against intent | v0.3 |
| `src/agentic_sidecar/evaluators/critic.py` | Critic mode — pre-decision challenge | v0.3 |
| `src/agentic_sidecar/evaluators/judge.py` | Model-agnostic LLM Judge interface | v0.3 |
| `src/agentic_sidecar/gate/` (full outcome set) | `WARN` / `CHALLENGE` / `REPLAN` / `PAUSE` / `ESCALATE`, human-in-the-loop escalation | v0.4 |
| `src/agentic_sidecar/gate/` (remaining outcomes) | `CHALLENGE` / `REPLAN` / `PAUSE` / `ESCALATE`, human-in-the-loop escalation (`ALLOW`/`WARN`/`BLOCK` shipped in v0.1/v0.2) | v0.4 |
| `src/agentic_sidecar/status/narrate.py` | Human-readable status narration | v0.5 |
| `src/agentic_sidecar/cli/` | CLI entry point (`agentic-sidecar status --follow`) | v0.5 |
| `src/agentic_sidecar/adapters/{crewai,autogen,openai_agents,google_adk}.py` | Additional framework adapters | v0.6 |
Expand All @@ -145,10 +153,17 @@ Full architecture and build order: [ROADMAP.md](ROADMAP.md).
- AgenticLens integration is optional (`agentic_sidecar.integrations.agenticlens`)
and must auto-skip in tests if `agenticlens` is not installed.
- `core/` must not import from `adapters/` (adapters depend on core, not the
reverse).
reverse). `core/` *does* import from `gate/` and `intent/` directly
(`Sidecar` wires in Policy Advisor, Risk Evaluator, and Intent Guardian as
built-in Decision Gate modules) — that's the expected direction, not an
exception to this rule. The distinction: `gate/`/`intent/` are modules
Sidecar orchestrates itself; `adapters/` are alternate entry points into
Sidecar, one per framework, and core has no business knowing any of them
exist.
- `gate/` (Policy, Risk) must work with zero dependency on `evaluators/`
(Planner, Critic, Judge) — v0.1's Decision Gate has to function before
Judge exists at all.
(Planner, Critic, Judge) or `intent/` — v0.1's Decision Gate has to
function before Judge or Intent Guardian exist at all, and Policy/Risk
answer different questions than Intent (see Design Constraint 5).
- `evaluators/judge.py` must stay model-agnostic — no hardcoded provider SDK
imports at module scope.

Expand Down
153 changes: 150 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,156 @@ All notable changes to this project are documented here.

## [Unreleased]

## [0.2.0] - 2026-08-15

### Added

- Intent Guardian (`agentic_sidecar.intent`): `IntentEnvelope` (goal,
requester, constraints, authority, expiry — concept.md §6), `Requester`,
`ConstraintBinding` (binds one envelope constraint to a specific tool
argument and comparison op), `IntentGuardian` (mirrors
`PolicyAdvisor`/`RiskEvaluator`'s construction shape), and
`evaluate_alignment()`. Scope is deliberately narrow: constraint
validation only (numeric/enum/allow-list, e.g. `maximum_refund: 500` vs.
a proposed `850`) and envelope-expiry detection. `authority` is carried
on the envelope (matching concept.md §6's shape, for future
`ai-operations-spec` alignment) but has no binding/enforcement mechanism
yet — deferred for the same reason Design Constraint 4 defers a
model-based risk classifier: build it once a real scenario motivates the
shape, not speculatively.
- `WARN` added to `Decision.status` (previously `ALLOW`/`BLOCK` only) —
Intent Guardian's outcome for a finding worth surfacing (a stale/expired
envelope) but not severe enough to block.
- Govern mode (`Sidecar(mode="govern")`): a `BLOCK` decision is now
actually enforced. `agentic_sidecar.core.exceptions.SidecarBlockedError`
is raised by an adapter (not by `Sidecar.evaluate()` itself, which only
ever computes a `Decision` — see its docstring) when Govern mode's
`BLOCK` should stop the call. `agentic_sidecar.adapters.langgraph.attach`
now raises it instead of calling the real tool when
`sidecar.mode == "govern"` and the decision is `BLOCK`; `WARN` and
`ALLOW` still call through in both modes.
- `Sidecar.set_intent(guardian)` — swaps the active `IntentGuardian`
between tasks (an `IntentEnvelope` is meant to be per-task, concept.md
§6, not fixed for a Sidecar's whole lifetime). Raises if `intent=...` is
given (at construction or via `set_intent`) without `"intent_guardian"`
in `roles` — the same "no silent gap" principle `on_sidecar_failure`
already applies, extended to this footgun.
- `"intent_guardian"` is now a supported `Sidecar` role (previously raised
`NotImplementedError` naming v0.2).
- `core/context.py`: `IntentSnapshot` (goal + constraints only — the
lightweight view attached to `DecisionContext.intent`, not the full
`IntentEnvelope`, which `core/` does not depend on) and `HistoryEntry`.
`Sidecar.evaluate()` now injects both into every `DecisionContext` before
dispatching to an evaluator (concept.md §7, Intent Injection), built from
`self.decisions` and the active `IntentGuardian` automatically.
- `core/operators.py`: shared `ArgOp` + `compare()`, extracted so
`gate/risk.py`'s argument-pattern rules and `intent/alignment.py`'s
constraint bindings don't duplicate identical comparator logic.
`gate/risk.py` refactored to use it; its own rule-matching behavior is
unchanged.
- `examples/langgraph_intent_guardian_govern_mode.py` — the refund-limit
scenario from concept.md §9 end to end against a real
`langgraph.prebuilt.create_react_agent` agent: an $850 refund request
raises `SidecarBlockedError` before the real tool runs; a $120 request
goes through normally.
- Test suite extended: `test_operators.py`, `test_envelope.py`,
`test_alignment.py`, `test_exceptions.py`, plus new coverage in
`test_sidecar.py` and `test_langgraph_adapter.py` for Govern mode, the
intent/role consistency checks, and injected intent/history.

### Fixed

- `risk_block_threshold` was never validated at construction — an
unrecognized value (e.g. a typo like `"SEVERE"`) passed straight through
`Sidecar.__init__` and only surfaced as a `KeyError` deep inside
`evaluate()`, silently resolved via `on_sidecar_failure` instead of
failing fast. A misconfigured threshold could therefore fail open on a
genuinely high-risk action. Now validated against `RISK_ORDER` at
construction, raising immediately.
- `IntentEnvelope.is_expired()` raised an unhandled `TypeError` for a naive
(no `tzinfo`) `expires` value — a realistic input shape from YAML or a
caller that forgot `tzinfo=timezone.utc` — comparing it against the
timezone-aware `datetime.now(timezone.utc)`. Inside `evaluate()` that
error was swallowed into `on_sidecar_failure`'s fallback instead of
producing the deterministic intent-expiry `WARN` it should have. Now
rejected explicitly, at `IntentEnvelope` construction (a `field_validator`
on `expires`) and in `is_expired()`'s own `now=` parameter, with an error
naming the fix rather than a bare `TypeError`.
- `SidecarBlockedError`, raised by the LangGraph adapter in Govern mode,
carried the bare pre-evaluation `DecisionContext` the adapter built, not
the one Intent Guardian actually evaluated — `Sidecar.evaluate()`
injected `intent`/`history` into a *copy* (`context.model_copy(...)`)
rather than the object the caller held, so `SidecarBlockedError.context`
always had `intent=None`, even when an intent-drift finding was exactly
why the call was blocked. `evaluate()` now injects by mutating the
caller's `DecisionContext` in place (documented as intentional on the
model itself — it's why `DecisionContext`, unlike `Decision`, isn't
frozen), so any caller's own reference — not just `sidecar.decisions` —
reflects the fully-evaluated context once `evaluate()` returns.
- ROADMAP.md's v0.2 deliverable cited concept.md §22 (the DEV/production
cleanup scenario, actually used by the v0.2.x benchmark) for the
refund-limit worked example; corrected to §9, which is where that
scenario actually appears.

## [0.1.0] - 2026-08-15

### Added

- Sidecar runtime (`agentic_sidecar.core`): `Sidecar`, `Decision(status,
risk, reason)`, `DecisionContext`. `on_sidecar_failure: fail_open |
fail_closed` is a required setting with no default; both paths are
tested. `roles` validates against v0.1's supported set (`policy`, `risk`)
and raises `NotImplementedError` (naming the version) for roles planned
but not yet built, rather than silently ignoring them.
- Decision Gate (`agentic_sidecar.gate`): YAML-driven Policy Advisor
(`policy.py`, allow/deny rules by tool-name glob) and rule-based Risk
Evaluator (`risk.py`, tool-name glob plus an optional argument-pattern
check). Zero LLM calls, per ROADMAP.md's Design Constraint 2.
- LangGraph adapter (`agentic_sidecar.adapters.langgraph.attach`): wraps a
list of tool callables so every call is evaluated by a `Sidecar` first.
v0.1 ships Observe mode only — the wrapped call always executes; nothing
yet enforces a `BLOCK`. No import-time dependency on the `langgraph`
package itself; a `langgraph` extra is declared in `pyproject.toml` for
code that actually builds a graph around the wrapped tools.
- `examples/langgraph_refund_observe_mode.py` — a runnable, offline
(no API key) example against a real `langgraph.prebuilt.create_react_agent`
agent, demonstrating a Policy Advisor deny rule and a Risk Evaluator
argument-threshold rule both firing in Observe mode.
- Test suite covering `Decision`, `DecisionContext`, `PolicyAdvisor`,
`RiskEvaluator`, `Sidecar` (including both `on_sidecar_failure` paths),
and the LangGraph adapter.

### Changed

- `Sidecar.attach(agent)` from README.md's Planned Python API is *not* how
v0.1 actually ships attach: `core/` must not import from `adapters/`
(AGENTS.md's Package Boundaries), so wrapping a specific framework's
tool-call surface is each adapter's own function
(`agentic_sidecar.adapters.langgraph.attach(sidecar, tools)`) rather than
a generic method on `Sidecar`. README.md documents both the real v0.1
shape and the longer-term generic shape this is expected to grow toward
once a second adapter exists (Design Constraint 1).

### Fixed

- ROADMAP.md's Release Status/summary described v0.1 as "Rule-Based
Decision Gate" without noting it's Observe-mode-only (advisory logging,
not enforcement) — a reader skimming just the top could overestimate
what shipped. Now says so explicitly in both places.
- ROADMAP.md's Package Layout diagram listed a `semantica.py` placeholder
under `integrations/` as if it already existed, alongside `agenticlens.py`
and `agentic_chaos.py`, which do. It doesn't yet (no code, no
`pyproject.toml` extra) — it's a v0.6 deliverable; the diagram now says
so. Same diagram also still described `core/sidecar.py` as owning
`attach()`, which isn't how v0.1 actually shipped it (see "Changed"
above) — corrected to match.
- ROADMAP.md's Design Constraints section header said "these four" while
listing five items.
- ROADMAP.md's top summary said v0.2-onward modules were "still unstarted"
when docstring-only placeholders for several of them already exist in
the tree — reworded to distinguish "no real logic yet" from "doesn't
exist yet."

## [0.0.1] - 2026-08-12

### Added
Expand Down Expand Up @@ -34,6 +184,3 @@ All notable changes to this project are documented here.
### Changed

- Renamed `future-plans.md` to `concept.md` and updated every reference.

No functional code has shipped yet — see [ROADMAP.md](ROADMAP.md) for the
v0.1 scope (Sidecar Runtime + Rule-Based Decision Gate).
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
Thanks for helping make `agentic-sidecar` better for everyone building
governable autonomous AI agents.

`agentic-sidecar` is currently a **scaffold** — see
`agentic-sidecar` has v0.1 (Sidecar Runtime + Rule-Based Decision Gate)
implemented; everything from v0.2 onward is still a **scaffold** — see
[ROADMAP.md](ROADMAP.md) for what's planned and in what order before
starting on a module.

Expand Down
Loading
Loading