4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
188 lines
8.5 KiB
Markdown
188 lines
8.5 KiB
Markdown
# OpenSRE architecture
|
|
|
|
How the OpenSRE codebase is structured: the seven first-party packages, what
|
|
each is responsible for, and which may depend on which. These dependency rules
|
|
are CI-enforced (`make check-imports`), so they are real invariants rather than
|
|
aspirations.
|
|
|
|
## The layer stack
|
|
|
|
The packages sit in four tiers. **Higher tiers may import lower tiers; a lower
|
|
tier may never import a higher one.** Packages on the same tier are peers — the
|
|
last column says whether peers may import each other.
|
|
|
|
| Tier | Packages | May import | Must never import | Peer rule |
|
|
| --- | --- | --- | --- | --- |
|
|
| 1 (top) | `surfaces`, `gateway` | `tools`, `integrations`, `core`, `platform`, `config` | — | Independent: must not import each other. |
|
|
| 2 | `tools` | `integrations`, `core`, `platform`, `config` | `surfaces`, `gateway` | May use an integration's client, so `integrations` effectively sits below it. |
|
|
| 2 | `integrations` | `core`, `platform`, `config` | `tools`, `surfaces`, `gateway` | Must never import `tools`; stays reusable below the tool layer. |
|
|
| 3 | `core`, `platform` | `config` | `surfaces`, `gateway`, `tools`, `integrations` | Siblings: **may** cross-import each other. |
|
|
| 4 (bottom) | `config` | — (nothing first-party) | everything above | Independent — imports no other first-party package. |
|
|
|
|
The shortcut: **dependencies point downward only.** A surface can reach all the
|
|
way down; `config` can reach nothing. The single deliberate exception is
|
|
`core ⟷ platform`, a mutually-dependent pair by design (see below).
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
subgraph T1["Tier 1 — surfaces"]
|
|
SURFACES[surfaces]
|
|
GATEWAY[gateway]
|
|
end
|
|
subgraph T2["Tier 2 — capability"]
|
|
TOOLS[tools]
|
|
INTEGRATIONS[integrations]
|
|
end
|
|
subgraph T3["Tier 3 — runtime + platform"]
|
|
CORE[core]
|
|
PLATFORM[platform]
|
|
end
|
|
subgraph T4["Tier 4 — config"]
|
|
CONFIG[config]
|
|
end
|
|
|
|
SURFACES --> TOOLS
|
|
SURFACES --> INTEGRATIONS
|
|
GATEWAY --> TOOLS
|
|
GATEWAY --> INTEGRATIONS
|
|
|
|
TOOLS --> CORE
|
|
TOOLS --> PLATFORM
|
|
INTEGRATIONS --> CORE
|
|
INTEGRATIONS --> PLATFORM
|
|
|
|
CORE <--> PLATFORM
|
|
|
|
CORE --> CONFIG
|
|
PLATFORM --> CONFIG
|
|
```
|
|
|
|
The arrows show edges between **adjacent** tiers to keep the diagram readable.
|
|
The actual rule is broader: a tier may import **any** tier below it, not only
|
|
the one directly beneath — so a surface may import `config` directly, and a
|
|
tool may import `platform`. Refer to the "May import" column above for the
|
|
complete set of allowed edges.
|
|
|
|
## The layers in detail
|
|
|
|
### Tier 1 — `surfaces` and `gateway`
|
|
|
|
The entry points a human or an external system talks to. Nothing first-party
|
|
may import from here, so a surface can be added or removed without touching the
|
|
layers below it.
|
|
|
|
- **`surfaces/`** — one folder per UI/client: `surfaces/cli` (the stateless
|
|
`opensre <command>` runner), `surfaces/interactive_shell` (the stateful
|
|
REPL), `surfaces/slack_app` (Slack bot), and `surfaces/shared` for code two
|
|
or more surfaces use. A surface owns its own I/O, prompts, and presentation,
|
|
and composes lower layers to do the actual work.
|
|
- **`gateway/`** — the standalone messaging gateway for inbound chat platforms
|
|
(`gateway/polling`, `gateway/session`, `gateway/storage`). A peer of
|
|
`surfaces`, not a child: the two never import each other.
|
|
|
|
### Tier 2 — `tools` and `integrations`
|
|
|
|
The capability layer — "do a thing against the outside world" — split by
|
|
responsibility:
|
|
|
|
- **`integrations/`** — the boundary for **user config and external clients**:
|
|
per-vendor config normalization, verification (`verifier.py`), API clients
|
|
(`client.py`), the store/catalog that resolves credentials, and
|
|
integration-local helpers. One folder per vendor (`integrations/datadog`,
|
|
`integrations/grafana`, `integrations/github`, …) plus cross-cutting pieces
|
|
like `integrations/hermes` and `integrations/llm_cli`.
|
|
- **`tools/`** — the **agent-callable** boundary: every `@tool(...)` function
|
|
and `BaseTool` subclass, the tool registry, framework subsystems
|
|
(`tools/investigation`, `tools/interactive_shell`), `tools/system/` for
|
|
tools with no vendor in their domain purpose (`fleet_monitoring`,
|
|
`python_execution_tool`, `sre_guidance_tool`, `watch_dog`), and
|
|
`tools/cross_vendor/` for tools whose logic spans 2+ vendor integrations
|
|
(`fix_sentry_issue`). See
|
|
[tool-placement-policy.md](tool-placement-policy.md) for the full decision
|
|
rule, including when a tool belongs under `integrations/<vendor>/tools/`
|
|
instead. A tool is what the planner selects and the runtime executes.
|
|
|
|
The import rule between them is one-directional: `integrations` must never
|
|
import `tools` (or `surfaces`), so a vendor client never depends on the agent
|
|
layer and stays reusable on its own. The reverse edge is allowed and common — a
|
|
tool reaches an integration's client for external data — so `integrations`
|
|
effectively sits one step below `tools` in the dependency graph. Do **not**
|
|
reintroduce top-level `vendors/` or `services/` packages — external-system code
|
|
belongs in `integrations/`, agent-callable code in `tools/`.
|
|
|
|
### Tier 3 — `core` and `platform`
|
|
|
|
The shared runtime and cross-cutting services the capability layer is built on.
|
|
|
|
- **`core/`** — the provider-agnostic agent runtime: the think → call tools →
|
|
observe loop (`core.agent.Agent`), agent/investigation state (`core/state`) and
|
|
context-budget enforcement (`core/context_budget.py`), the tool framework primitives
|
|
(`core/tool_framework`), shared LLM clients (`core/llm`), agent-harness
|
|
session handling (`core/agent_harness`), and pure domain rules (`core/domain`).
|
|
- **`platform/`** — cross-cutting services with no investigation logic of their
|
|
own: guardrails, masking, sandbox, analytics, auth, notifications,
|
|
observability, scheduler, and deployment. It deliberately shadows the stdlib
|
|
`platform` name and re-exposes it, so `import platform` still works.
|
|
|
|
These two are the one bidirectional pair by design: `core` reaches `platform`
|
|
for guardrails, masking, observability, and evidence/log compaction, while
|
|
`platform` reaches back into `core` for the shared state and session types
|
|
(`core.state`, `core.agent_harness.session`). Splitting them into
|
|
separate tiers would forbid that edge, so they share a tier as siblings.
|
|
|
|
### Tier 4 — `config`
|
|
|
|
The floor: shared constants, prompts, and UI theme. Everything above may
|
|
read from `config`, but `config`
|
|
imports no other first-party package — keeping it a leaf means constants can be
|
|
imported anywhere without dragging runtime along.
|
|
|
|
## Cross-layer flows
|
|
|
|
Two worked examples showing how control descends the stack and results flow back
|
|
up. Arrows only ever cross a boundary downward.
|
|
|
|
### An investigation from the CLI
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A["surfaces/cli\n opensre investigate"] --> B["tools/investigation\n capability + lifecycle"]
|
|
B --> C["core\n Agent runtime, context budget, LLM"]
|
|
B --> D["integrations\n vendor clients + credentials"]
|
|
C --> E["platform\n guardrails, masking, sandbox, observability"]
|
|
B --> F["config\n prompts + constants"]
|
|
```
|
|
|
|
1. `surfaces/cli` parses the command and hands off to the investigation
|
|
capability in `tools/investigation` — the surface never runs pipeline logic
|
|
itself.
|
|
2. `tools/investigation` drives the six-stage pipeline (see
|
|
[`investigation-pipeline-architecture.md`](investigation-pipeline-architecture.md)),
|
|
asking `core` to run the ReAct loop and select/execute tools.
|
|
3. Evidence-gathering tools reach `integrations` for vendor clients and resolved
|
|
credentials; `core` and `platform` supply the runtime, guardrails, and
|
|
masking around every call.
|
|
4. The structured diagnosis flows back up to the surface, which owns how it is
|
|
presented or delivered.
|
|
|
|
### An inbound gateway message
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A["gateway/polling\n inbound chat message"] --> B["gateway/session + storage\n resolve conversation state"]
|
|
B --> C["tools + core\n run the requested capability"]
|
|
C --> D["platform\n notifications, observability"]
|
|
```
|
|
|
|
`gateway` receives a message, resolves session state from its own storage, then
|
|
composes the same tier-2/tier-3 capability code a surface would — without ever
|
|
importing `surfaces`, since the two are independent tier-1 peers.
|
|
|
|
## Related docs
|
|
|
|
- [`AGENTS.md`](https://github.com/Tracer-Cloud/opensre/blob/main/AGENTS.md) —
|
|
repo map and per-area "files to touch" guides.
|
|
- [`investigation-pipeline-architecture.md`](investigation-pipeline-architecture.md)
|
|
— how a single investigation runs end-to-end within the `tools` + `core`
|
|
layers.
|