From d2df1457efb65495a7890e30c5e23d171a42d5f0 Mon Sep 17 00:00:00 2001 From: Khush Patel Date: Thu, 28 May 2026 17:57:37 +0530 Subject: [PATCH 1/3] chore(agentos): make vite dev proxy target env-configurable AGENTOS_API_TARGET env var overrides the hardcoded production api.clawagent.sh target. Defaults preserved (backwards-compatible). Lets developers point `vite dev` at a local computeragent-server without editing the config. Co-Authored-By: Claude Opus 4.7 --- agentos/vite.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/agentos/vite.config.ts b/agentos/vite.config.ts index 47ac941..2b624de 100644 --- a/agentos/vite.config.ts +++ b/agentos/vite.config.ts @@ -5,8 +5,10 @@ import react from "@vitejs/plugin-react"; // proxied to the Node server. For local `vite dev`, proxy /api to the live API // (api.clawagent.sh/agentos/api) and inject the Basic Auth header so the // dashboard works end-to-end against real data without deploying. +// Override AGENTOS_API_TARGET to point at a local server (e.g. http://127.0.0.1:8787). const API_USER = process.env.AGENTOS_API_USER ?? "clawagent"; const API_PASS = process.env.AGENTOS_API_PASS ?? ""; +const API_TARGET = process.env.AGENTOS_API_TARGET ?? "https://api.clawagent.sh"; const authHeader = "Basic " + Buffer.from(`${API_USER}:${API_PASS}`).toString("base64"); export default defineConfig({ @@ -14,7 +16,7 @@ export default defineConfig({ server: { proxy: { "/api": { - target: "https://api.clawagent.sh", + target: API_TARGET, changeOrigin: true, rewrite: (p) => p.replace(/^\/api/, "/agentos/api"), headers: { Authorization: authHeader }, From 8bc02fbfbfab1c7ce5209ff10ad53289602d0135 Mon Sep 17 00:00:00 2001 From: Khush Patel Date: Thu, 28 May 2026 17:58:05 +0530 Subject: [PATCH 2/3] feat(policy): SRS-backed per-agent guardrails (Cedar + OPA) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an engine-agnostic policy abstraction at the ComputerAgent layer. A PolicyDecider gates every tool call before the engine dispatches it; denies short-circuit with behavior:"deny" and never reach the tool. Why ComputerAgent-level, not per-engine: policy is the fourth orthogonal axis alongside engine/substrate/memory. Configure once at the harness; all engines (claude-agent-sdk, gitagent) inherit enforcement via the existing onPermissionRequest contract β€” engines don't need to know about Cedar/OPA/SRS. How it works: - protocol: PolicyDecider, ToolCallContext, PolicyDecision, PolicyConfig types; CreateSessionBody gains an optional policy field. - harness-server: SrsPolicyDecider fetches the RAI policy from SRS once, caches cedar_guardrail + opa_guardrail, calls /v1/guardrails/evaluate-tool-call per turn. run-session wraps onPermissionRequest so a bound decider gates ahead of any client mediation. - engine-claude-agent-sdk: PreToolUse hook added so the gate fires even in bypassPermissions mode (where canUseTool is skipped). gitagent already routed preToolUse β†’ onPermissionRequest. - sdk: ComputerAgent constructor accepts policy; forwarded into POST /v1/sessions. - AgentOS server: /agentos/api/policies/* proxy SRS (LYZR_API_KEY never reaches the browser); /agentos/api/opa-policies/* proxies SRS's standalone Rego policies. agent_policy_bindings collection in Mongo holds the per-agent policy_id binding. chat-sandbox reads the binding and forwards a policy spec to /sandboxes. - AgentOS UI: Policies page (list / create / edit / delete Cedar + OPA), Rego policy modal, per-agent policy tab with attach/detach. Mirrors the shape of Lyzr's SRS guardrail-evaluate endpoint: ToolCallContext β†’ {allowed, deniedBy, reason}. New policy engines drop in by implementing PolicyDecider and branching on PolicyConfig.kind in create-session. Verified end-to-end: claude-code denies Bash with destructive shell patterns (OPA), Write/Edit (Cedar), WebFetch outside an allowlist (OPA); safe Bash and allowlisted WebFetch pass through. Co-Authored-By: Claude Opus 4.7 --- agentos/src/App.tsx | 30 +- agentos/src/api.ts | 75 +++ agentos/src/components/PoliciesPage.tsx | 571 ++++++++++++++++++ agentos/src/components/PolicyTab.tsx | 137 +++++ examples/agent-policy-store.ts | 56 ++ examples/agentos-api.ts | 86 +++ examples/computeragent-server.ts | 23 +- examples/slack-bot.ts | 17 +- .../engine-claude-agent-sdk/src/engine.ts | 10 +- .../src/permission-bridge.ts | 39 +- .../src/services/create-session.ts | 14 + .../src/services/run-session.ts | 38 +- .../src/services/srs-policy-decider.ts | 97 +++ packages/harness-server/src/session.ts | 2 + packages/protocol/src/harness-rest.ts | 15 + packages/protocol/src/index.ts | 1 + packages/protocol/src/policy.ts | 62 ++ packages/sdk/src/computer-agent.ts | 1 + packages/sdk/src/types.ts | 14 + 19 files changed, 1272 insertions(+), 16 deletions(-) create mode 100644 agentos/src/components/PoliciesPage.tsx create mode 100644 agentos/src/components/PolicyTab.tsx create mode 100644 examples/agent-policy-store.ts create mode 100644 packages/harness-server/src/services/srs-policy-decider.ts create mode 100644 packages/protocol/src/policy.ts diff --git a/agentos/src/App.tsx b/agentos/src/App.tsx index 09aaaf1..862ebd5 100644 --- a/agentos/src/App.tsx +++ b/agentos/src/App.tsx @@ -4,9 +4,11 @@ import { LogsTab } from "./components/LogsTab.tsx"; import { WorkspaceTab } from "./components/WorkspaceTab.tsx"; import { SchedulesTab } from "./components/SchedulesTab.tsx"; import { HomePage } from "./components/HomePage.tsx"; +import { PolicyTab } from "./components/PolicyTab.tsx"; +import { PoliciesPage } from "./components/PoliciesPage.tsx"; -type Tab = "chat" | "schedules" | "logs"; -type View = "home" | "dashboard"; +type Tab = "chat" | "schedules" | "policy" | "logs"; +type View = "home" | "dashboard" | "policies"; function timeAgo(iso: string | null): string { if (!iso) return "never"; @@ -91,7 +93,7 @@ export default function App() { -
+
+
{/* Agents folder (file-system style) */}
@@ -145,7 +155,9 @@ export default function App() { {/* Main */}
- {view === "home" ? ( + {view === "policies" ? ( + + ) : view === "home" ? ( agents[0] && openAgent(agents[0].name)} /> ) : agent ? ( <> @@ -161,7 +173,7 @@ export default function App() {