docs(diagrams): comprehensive architecture diagram pass (SVG) across the published docs #59
@@ -5,10 +5,24 @@ description: System architecture, components, infrastructure, and communication
|
||||
|
||||
# Architecture
|
||||
|
||||
Molecule AI is a platform for orchestrating AI agent workspaces that form an organizational hierarchy. Workspaces register with a central platform, communicate via A2A (Agent-to-Agent) protocol, and are visualized on a drag-and-drop canvas.
|
||||
Molecule AI is an **open-source operating system for AI agent organizations** — run the entire stack yourself (self-hosted) or use the hosted SaaS. It orchestrates agent **workspaces** that form an organizational hierarchy: each workspace registers with a control plane, runs on its **own dedicated machine**, communicates over the A2A (Agent-to-Agent) protocol, and appears live on a drag-and-drop canvas. The core is **provider-agnostic** — runtimes, models, and even physical devices are pluggable — so the ecosystem grows without forking the platform.
|
||||
|
||||
## System Overview
|
||||
|
||||
<img
|
||||
src="/diagrams/platform-architecture.svg"
|
||||
alt="Molecule AI platform architecture: operator surfaces (Canvas, CLI, MCP server, channels, REST) drive a Go control plane (provisioner, registry/discovery with CanCommunicate ACL, A2A proxy, WebSocket hub, scheduler, secrets, audit) backed by Postgres and Redis; the control plane provisions an isolated org tenant of workspace containers that communicate directly peer-to-peer over A2A governed by the org hierarchy; runtimes (claude-code, langgraph, crewai, autogen, deepagents, openclaw, hermes, gemini-cli, google-adk, external) and model providers (Anthropic, OpenAI, Google Vertex, OpenRouter) are pluggable integrations."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
Three properties define the architecture:
|
||||
|
||||
- **Hard isolation by machine.** Every workspace is one agent on its **own dedicated machine** (own OS, filesystem, secrets). Workspaces **cannot** read each other's environment — there is no shared disk or shared process space. **A2A over the network is the only sanctioned channel**, and it is gated by the org hierarchy (`CanCommunicate`).
|
||||
- **Anything can be a runtime.** Behind one `BaseAdapter` contract, a workspace can be any agent framework (claude-code, langgraph, crewai, autogen, deepagents, openclaw, hermes, gemini-cli, **google-adk**), an external/BYO agent, or — on the roadmap — an **intelligent device**: smart glasses, watches, robots, home/building systems, vehicles. Any A2A/MCP-speaking endpoint joins the org as a governed workspace. Models are equally pluggable (Anthropic, OpenAI/-compatible, **Google Vertex/Gemini**, OpenRouter).
|
||||
- **Deep, namespaced memory.** A hierarchical memory architecture (HMA) gives each workspace a durable namespace and three scopes — **LOCAL** (private), **TEAM** (parent + siblings), **GLOBAL** (org-wide) — whose reach follows the same org tree as communication.
|
||||
|
||||
A text summary of the same flow:
|
||||
|
||||
```
|
||||
Canvas (Next.js :3000) <--WebSocket--> Platform (Go :8080) <--HTTP--> Postgres + Redis
|
||||
|
|
||||
|
||||
@@ -5,6 +5,12 @@ description: Connect workspaces to Telegram, Slack, Discord, and Lark/Feishu for
|
||||
|
||||
## Overview
|
||||
|
||||
<img
|
||||
src="/diagrams/channels.svg"
|
||||
alt="Channel message flow: a chat platform (Telegram, Slack, Discord, Lark) delivers an inbound user message to POST /webhooks/:type; the control-plane adapter parses it, checks an allowlist, and forwards it over A2A to the target workspace agent; the agent's reply routes back out through the same adapter to the user."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
Channels let workspaces send and receive messages on social platforms. Each
|
||||
workspace can have multiple channel integrations — a Telegram bot, a Slack
|
||||
webhook, a Discord webhook, a Lark/Feishu Custom Bot — configured independently with per-channel
|
||||
|
||||
@@ -3,6 +3,12 @@ title: Concepts
|
||||
description: The core primitives that compose every Molecule AI org — workspaces, plugins, channels, schedules, tokens, external agents, and the canvas.
|
||||
---
|
||||
|
||||
<img
|
||||
src="/diagrams/concepts-overview.svg"
|
||||
alt="Molecule AI core concepts: an org.yaml is imported by the Control Plane, which provisions a tenant of agent workspaces that communicate peer-to-peer over A2A — governed by the org hierarchy — while the Canvas streams live state and external agents join over HTTP."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## Workspaces
|
||||
|
||||
A **workspace** is a real Docker container running a real LLM agent. Each
|
||||
|
||||
@@ -10,6 +10,14 @@ cloud, an edge device, or your laptop — that join the Molecule AI canvas as
|
||||
first-class workspaces. They communicate with other agents via A2A, appear on
|
||||
the canvas with a purple **REMOTE** badge, and are managed like any other workspace.
|
||||
|
||||
Like every workspace, they speak the A2A task protocol. Its lifecycle and the discovery → direct-call flow:
|
||||
|
||||
<img
|
||||
src="/diagrams/a2a-lifecycle.svg"
|
||||
alt="A2A task lifecycle: a task moves submitted → working → completed (with artifacts), failed, or canceled, with a working ↔ input-required loop when the agent needs a caller reply; message/send is synchronous and message/sendSubscribe streams SSE events where the terminal event closes the stream. Below, the discovery sequence: caller asks the platform GET /registry/discover/:id, the platform applies CanCommunicate and returns the target URL (or 403), then the caller calls the target agent directly over A2A — the platform is not in the data path."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
<Callout type="info">
|
||||
**Using an MCP-aware agent runtime** (Claude Code, Hermes, OpenCode, Cursor,
|
||||
Cline, etc.)? The universal `molecule-mcp` wheel handles registration,
|
||||
|
||||
@@ -15,6 +15,16 @@ The `google-adk` runtime adapter integrates [Google's Agent Development Kit](htt
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
A `google-adk` workspace runs Google's ADK engine (`LlmAgent` + `Runner` + `McpToolset`); a Molecule-authored A2A executor bridges ADK `Runner` events into the platform's a2a-1.x event model, so the agent is a fully governed citizen of the org. Platform tools reach the agent over **MCP**, and Gemini is served by **Vertex AI using keyless credentials** (Application Default Credentials over Workload Identity Federation — no API key on disk).
|
||||
|
||||
<img
|
||||
src="/diagrams/architecture-keyless-adk.svg"
|
||||
alt="End-to-end google-adk architecture: Canvas declarative intent to Control Plane provisioning to a per-agent ADK runtime (LlmAgent + Runner + Molecule A2A executor + McpToolset), with a keyless Workload Identity Federation chain (GCP STS to a least-privilege service account to Vertex AI gemini-2.5-pro) — zero API keys."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## When to use Google ADK vs other runtimes
|
||||
|
||||
| | Google ADK | LangGraph | AutoGen |
|
||||
|
||||
@@ -9,6 +9,12 @@ import { Callout } from 'fumadocs-ui/components/callout';
|
||||
|
||||
Hermes is Molecule AI's built-in inference router powering `runtime: hermes` workspaces. It supports three dispatch paths — a native Anthropic Messages API path, a native Gemini `generateContent` path, and an OpenAI-compatible shim for 13+ other providers — keyed automatically by which API secret is present on the workspace.
|
||||
|
||||
<img
|
||||
src="/diagrams/hermes-dispatch.svg"
|
||||
alt="Hermes multi-provider dispatch: a key-priority resolver checks workspace secrets in order (HERMES_API_KEY, then OPENROUTER_API_KEY, then ANTHROPIC_API_KEY, then GEMINI_API_KEY) and routes into one of three transports — native Anthropic /v1/messages, native Gemini generateContent, or an OpenAI-compatible shim for 13+ providers (OpenRouter, DeepSeek, Together, and any OpenAI-compatible gateway). If the chosen path's SDK is not installed, Hermes raises a RuntimeError at startup rather than silently falling back."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
Phases 2a through 2e are fully merged to `main`:
|
||||
|
||||
- **Phase 2a** (PR #240) — native Anthropic dispatch
|
||||
|
||||
@@ -7,6 +7,12 @@ The Molecule AI MCP server lets any MCP-compatible AI agent (Claude Code,
|
||||
Cursor, etc.) manage workspaces, agents, secrets, memory, schedules,
|
||||
channels, and more through the platform API.
|
||||
|
||||
<img
|
||||
src="/diagrams/mcp-tools.svg"
|
||||
alt="MCP as one tool surface in two directions: on the left, any MCP host (Claude Desktop/Code, Cursor, your own client) connects via @molecule-ai/mcp-server over stdio to drive the platform; in the center, the platform exposes 80+ tools 1:1 with API routes (workspaces, delegation, memory, secrets, schedules, approvals, files, channels) with auth and hierarchy ACL applied; on the right, in-workspace runtimes (claude-code, google-adk via McpToolset, langgraph, external) consume the same tools natively — no per-framework tool glue."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## Quick start
|
||||
|
||||
### Install
|
||||
|
||||
@@ -7,6 +7,12 @@ description: Deploy entire multi-workspace organizations from a single YAML file
|
||||
|
||||
Org templates let you define an entire agent organization -- hierarchy of workspaces with roles, configurations, and relationships -- in a single YAML file. Import one template and the platform provisions every workspace, wires parent-child relationships, seeds schedules, and installs plugins automatically.
|
||||
|
||||
<img
|
||||
src="/diagrams/org-template.svg"
|
||||
alt="org.yaml on the left (org_name, defaults, nested workspaces with roles/runtimes/children) imports into a rendered org chart on the right; children become parent_id nesting, defaults merge by union with per-workspace overrides and !name opt-outs, and schedules/plugins are seeded on import."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## YAML Structure
|
||||
|
||||
A minimal org template looks like this:
|
||||
|
||||
@@ -5,6 +5,12 @@ description: Run recurring prompts on cron schedules — automated audits, repor
|
||||
|
||||
## Overview
|
||||
|
||||
<img
|
||||
src="/diagrams/schedules.svg"
|
||||
alt="Schedule lifecycle: a 30s scheduler loop reads due rows from workspace_schedules, passes them through a concurrency semaphore (max 10, 5-minute timeout), fires an A2A message/send to the workspace agent as system:scheduler, then records the outcome (success/error/skipped) and recomputes next_run back into the table."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
Schedules let you run recurring prompts against a workspace on a cron schedule.
|
||||
Each tick fires an A2A `message/send` into the workspace, so the agent
|
||||
processes the prompt as if it received a normal message. This enables automated
|
||||
|
||||
@@ -5,6 +5,14 @@ description: Mapping the OWASP Agentic AI Top 10 to Molecule AI security control
|
||||
|
||||
## Overview
|
||||
|
||||
The platform's primary access-control mechanism is hierarchy-based: the org chart itself is the policy that governs which agents may communicate, what memory they reach, and which events they see — backed by per-machine isolation underneath.
|
||||
|
||||
<img
|
||||
src="/diagrams/governance-trust.svg"
|
||||
alt="Governance model: CanCommunicate(caller, target) allows self, siblings, and parent↔child edges (green) and denies skip-level and cross-team edges (red, 403) across the org tree; the same hierarchy scopes A2A messaging, LOCAL/TEAM/GLOBAL memory reach, ACL-filtered WebSocket event fan-out, and peer discovery; underneath, each workspace is its own machine with no shared filesystem, env, or secrets — defense in depth with the ACL above and machine isolation below."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
This page documents Molecule AI's coverage of the
|
||||
[OWASP Agentic AI Top 10](https://owasp.org/agentic-ai-top-10/) security risks
|
||||
for AI agents and agentic systems. Coverage is assessed against the platform as
|
||||
|
||||
@@ -3,6 +3,14 @@ title: Self-Hosting
|
||||
description: Run the full Molecule AI stack on your own infrastructure.
|
||||
---
|
||||
|
||||
Molecule AI is open source and runs entirely on your own infrastructure — the same binary as the hosted SaaS, in single-org mode. The whole stack sits on one Docker network:
|
||||
|
||||
<img
|
||||
src="/diagrams/self-hosting.svg"
|
||||
alt="Self-hosting topology on the molecule-monorepo-net Docker network: the Canvas (Next.js :3000) talks to the Platform (Go :8080) over REST and WebSocket; the platform connects to Postgres (:5432, source of truth), Redis (:6379, liveness and pub/sub), Langfuse (:3001, traces, with ClickHouse), and Temporal (:7233/:8233, durable workflows), and provisions tiered workspace containers that register and heartbeat back. Secrets are encrypted at rest with AES-256-GCM or a KMS envelope; the platform refuses to boot without an encryption key. SaaS adds a Cloudflare wildcard-DNS edge that self-host omits."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Requirement | Minimum Version |
|
||||
|
||||
@@ -7,6 +7,14 @@ Workspace bearer tokens authenticate agents and API clients against the
|
||||
Molecule AI platform. Each token is scoped to a single workspace — a token
|
||||
from workspace A cannot access workspace B.
|
||||
|
||||
These workspace bearer tokens are the narrowest of three credential tiers — sitting below org API keys and the control-plane admin token. The full model:
|
||||
|
||||
<img
|
||||
src="/diagrams/token-model.svg"
|
||||
alt="Three scoped credential tiers, authority narrowing top to bottom: ADMIN_TOKEN authorizes the whole control plane and all orgs (mints org keys); an Org API key authorizes one entire org and nothing on the control plane or other orgs; a Workspace bearer token (256-bit, sha256-stored, shown once) authorizes only its own workspace and is the only credential an agent holds. All secrets are encrypted at rest and masked on read."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
## Endpoints
|
||||
|
||||
All endpoints are behind `WorkspaceAuth` middleware — you need an existing
|
||||
|
||||
@@ -9,6 +9,12 @@ import { Callout } from 'fumadocs-ui/components/callout';
|
||||
|
||||
Every Molecule AI workspace is backed by a `config.yaml` file. The **Config tab** in the canvas lets you edit this file through a structured form or in raw YAML mode. Changes take effect on the next workspace restart.
|
||||
|
||||
<img
|
||||
src="/diagrams/workspace-config.svg"
|
||||
alt="config.yaml drives runtime resolution: the workspace loads config.yaml, selects an adapter from the registry by its runtime field (claude-code, langgraph, hermes, google-adk, external, etc.), and runs a boot pipeline — preflight, setup, create_executor, system prompt + agent card, register, heartbeat, serve A2A. Model is provider:model-id; tools are tier-gated; preflight fails loud on a runtime/config mismatch."
|
||||
style={{ width: '100%', height: 'auto', margin: '1rem 0' }}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## Opening the Config tab
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 620" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
<marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#ef4444"/></marker>
|
||||
<marker id="ab" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#f59e0b"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="620" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">A2A task lifecycle</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">A caller sends a message (JSON-RPC); the agent's task moves through states and streams events. Terminal SSE event ends the stream — no polling.</text>
|
||||
|
||||
<!-- state machine -->
|
||||
<g filter="url(#sh)"><rect x="40" y="100" width="1120" height="270" rx="14" fill="#ffffff" stroke="#cdd3df" stroke-width="1.5"/></g>
|
||||
<text x="60" y="128" font-size="13.5" font-weight="700" fill="#0f172a">Task states</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="80" y="190" width="150" height="60" rx="10" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.4"/></g>
|
||||
<text x="155" y="216" font-size="13" font-weight="700" fill="#3730a3" text-anchor="middle">submitted</text>
|
||||
<text x="155" y="234" font-size="10" fill="#6366f1" text-anchor="middle">message accepted</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="320" y="190" width="150" height="60" rx="10" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.4"/></g>
|
||||
<text x="395" y="216" font-size="13" font-weight="700" fill="#b45309" text-anchor="middle">working</text>
|
||||
<text x="395" y="234" font-size="10" fill="#92560a" text-anchor="middle">agent executing</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="320" y="296" width="150" height="56" rx="10" fill="#fffbeb" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="4 3"/></g>
|
||||
<text x="395" y="320" font-size="12" font-weight="700" fill="#b45309" text-anchor="middle">input-required</text>
|
||||
<text x="395" y="338" font-size="9.5" fill="#92560a" text-anchor="middle">needs caller reply</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="600" y="150" width="150" height="56" rx="10" fill="#ecfdf5" stroke="#10b981" stroke-width="1.5"/></g>
|
||||
<text x="675" y="174" font-size="13" font-weight="700" fill="#047857" text-anchor="middle">completed</text>
|
||||
<text x="675" y="192" font-size="9.5" fill="#0f766e" text-anchor="middle">+ artifacts</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="600" y="234" width="150" height="50" rx="10" fill="#fef2f2" stroke="#ef4444" stroke-width="1.4"/></g>
|
||||
<text x="675" y="264" font-size="13" font-weight="700" fill="#b91c1c" text-anchor="middle">failed</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="600" y="304" width="150" height="50" rx="10" fill="#f8fafc" stroke="#94a3b8" stroke-width="1.4"/></g>
|
||||
<text x="675" y="334" font-size="13" font-weight="700" fill="#475569" text-anchor="middle">canceled</text>
|
||||
|
||||
<!-- transitions -->
|
||||
<path d="M230,220 L320,220" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
<path d="M470,212 L600,180" stroke="#10b981" stroke-width="1.8" fill="none" marker-end="url(#ag)"/><text x="540" y="188" font-size="10" fill="#047857">success</text>
|
||||
<path d="M470,232 L600,255" stroke="#ef4444" stroke-width="1.6" fill="none" marker-end="url(#ar)"/><text x="540" y="256" font-size="10" fill="#b91c1c">error</text>
|
||||
<path d="M395,250 L395,296" stroke="#f59e0b" stroke-width="1.5" fill="none" marker-end="url(#ab)"/>
|
||||
<path d="M320,324 C260,324 260,238 318,228" stroke="#f59e0b" stroke-width="1.5" fill="none" stroke-dasharray="5 4" marker-end="url(#ab)"/><text x="232" y="290" font-size="10" fill="#b45309">caller replies</text>
|
||||
<path d="M470,326 C540,326 560,332 600,330" stroke="#94a3b8" stroke-width="1.5" fill="none" marker-end="url(#a)"/><text x="500" y="346" font-size="10" fill="#475569">tasks/cancel</text>
|
||||
|
||||
<!-- transports note -->
|
||||
<rect x="820" y="150" width="320" height="200" rx="11" fill="#f8fafc" stroke="#cdd3df"/>
|
||||
<text x="838" y="176" font-size="12.5" font-weight="700" fill="#15181f">Transports</text>
|
||||
<text x="838" y="198" font-size="11" fill="#475569"><tspan font-family="monospace" fill="#4f46e5">message/send</tspan> — sync request/response</text>
|
||||
<text x="838" y="218" font-size="11" fill="#475569"><tspan font-family="monospace" fill="#4f46e5">message/sendSubscribe</tspan> — SSE stream</text>
|
||||
<text x="838" y="244" font-size="11.5" font-weight="700" fill="#15181f">Streaming events (SSE)</text>
|
||||
<text x="838" y="264" font-size="11" fill="#475569">each state change emits an event;</text>
|
||||
<text x="838" y="281" font-size="11" fill="#475569">the <tspan font-weight="700">terminal</tspan> event closes the stream.</text>
|
||||
<text x="838" y="304" font-size="11.5" font-weight="700" fill="#15181f">Cancel</text>
|
||||
<text x="838" y="324" font-size="11" fill="#475569"><tspan font-family="monospace">tasks/cancel</tspan> → executor interrupt</text>
|
||||
|
||||
<!-- sequence -->
|
||||
<text x="40" y="410" font-size="13.5" font-weight="700" fill="#0f172a">Discovery + direct call (platform exits the data path)</text>
|
||||
<g filter="url(#sh)"><rect x="40" y="426" width="1120" height="160" rx="13" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/></g>
|
||||
<!-- lanes -->
|
||||
<text x="120" y="452" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Caller agent</text>
|
||||
<text x="430" y="452" font-size="12" font-weight="700" fill="#4f46e5" text-anchor="middle">Platform (discovery)</text>
|
||||
<text x="800" y="452" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Target agent</text>
|
||||
<line x1="120" y1="460" x2="120" y2="576" stroke="#e2e8f0" stroke-width="1.5"/>
|
||||
<line x1="430" y1="460" x2="430" y2="576" stroke="#e2e8f0" stroke-width="1.5"/>
|
||||
<line x1="800" y1="460" x2="800" y2="576" stroke="#e2e8f0" stroke-width="1.5"/>
|
||||
<path d="M120,478 L430,478" stroke="#64748b" stroke-width="1.5" fill="none" marker-end="url(#a)"/><text x="135" y="472" font-size="10.5" fill="#475569">① GET /registry/discover/:id</text>
|
||||
<path d="M430,506 L120,506" stroke="#64748b" stroke-width="1.5" fill="none" marker-end="url(#a)" stroke-dasharray="5 4"/><text x="150" y="500" font-size="10.5" fill="#475569">② CanCommunicate ✓ → target URL (403 if denied)</text>
|
||||
<path d="M120,540 L800,540" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#ag)"/><text x="300" y="534" font-size="10.5" font-weight="700" fill="#047857">③ direct A2A message/send (platform NOT in path)</text>
|
||||
<path d="M800,566 L120,566" stroke="#10b981" stroke-width="1.6" fill="none" marker-end="url(#ag)" stroke-dasharray="5 4"/><text x="320" y="560" font-size="10.5" fill="#047857">④ task events / result</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
@@ -0,0 +1,201 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 980" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/>
|
||||
</filter>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#64748b"/>
|
||||
</marker>
|
||||
<marker id="arrowGold" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7.5" markerHeight="7.5" orient="auto-start-reverse">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#d97706"/>
|
||||
</marker>
|
||||
<marker id="arrowBlue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7.5" markerHeight="7.5" orient="auto-start-reverse">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#1a73e8"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<rect width="1480" height="980" fill="#fbfcfe"/>
|
||||
|
||||
<!-- Header -->
|
||||
<text x="48" y="56" font-size="30" font-weight="700" fill="#15181f">Molecule AI — From One Agent to a Governed AI Org</text>
|
||||
<text x="48" y="86" font-size="15.5" fill="#5b6472">Net-new <tspan font-weight="600" fill="#1a73e8">Gemini</tspan> agents on <tspan font-weight="600" fill="#1a73e8">Google ADK</tspan> · tools over <tspan font-weight="600" fill="#7c3aed">MCP</tspan> · served by <tspan font-weight="600" fill="#1a73e8">Vertex AI</tspan> with <tspan font-weight="700" fill="#b45309">keyless (WIF/ADC)</tspan> credentials — zero key material anywhere</text>
|
||||
|
||||
<!-- keyless badge -->
|
||||
<g transform="translate(1086,30)">
|
||||
<rect width="346" height="48" rx="10" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.5"/>
|
||||
<text x="20" y="22" font-size="14.5" font-weight="700" fill="#b45309">🔒 Keyless by design</text>
|
||||
<text x="20" y="39" font-size="12.5" fill="#92560a">No API keys · no long-lived secrets · AWS→GCP federation</text>
|
||||
</g>
|
||||
|
||||
<!-- ============ STEP 1: Operator / Canvas ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="48" y="150" width="300" height="120" rx="14" fill="#f6f4ff" stroke="#7c6df2" stroke-width="1.5"/>
|
||||
</g>
|
||||
<circle cx="74" cy="176" r="13" fill="#7c6df2"/><text x="74" y="181" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">1</text>
|
||||
<text x="98" y="181" font-size="15" font-weight="700" fill="#3b2fae">Operator · Molecule Canvas</text>
|
||||
<text x="68" y="212" font-size="13.5" fill="#15181f" font-weight="600">Declarative intent — org.yaml</text>
|
||||
<text x="68" y="234" font-size="12.5" fill="#5b6472">roles · charters · model · tools</text>
|
||||
<text x="68" y="254" font-size="12.5" fill="#5b6472">“describe the org, don’t wire the code”</text>
|
||||
|
||||
<!-- ============ STEP 2: Control Plane ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="48" y="312" width="300" height="200" rx="14" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
|
||||
</g>
|
||||
<circle cx="74" cy="338" r="13" fill="#4f46e5"/><text x="74" y="343" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">2</text>
|
||||
<text x="98" y="343" font-size="15" font-weight="700" fill="#3730a3">Control Plane · Railway</text>
|
||||
<rect x="68" y="362" width="260" height="62" rx="9" fill="#ffffff" stroke="#c7cdf5"/>
|
||||
<text x="82" y="386" font-size="13.5" font-weight="600" fill="#15181f">Provisioner</text>
|
||||
<text x="82" y="405" font-size="12" fill="#5b6472">renders per-agent EC2 user-data;</text>
|
||||
<text x="82" y="419" font-size="12" fill="#5b6472">injects keyless ADC cred-config</text>
|
||||
<rect x="68" y="434" width="260" height="62" rx="9" fill="#fff7ed" stroke="#f4c98a"/>
|
||||
<text x="82" y="458" font-size="13.5" font-weight="600" fill="#b45309">envs.yaml — SSOT</text>
|
||||
<text x="82" y="477" font-size="12" fill="#92560a">vertex: project / location</text>
|
||||
<text x="82" y="491" font-size="12" fill="#92560a">GCP_WIF_CRED_CONFIG_JSON (non-secret)</text>
|
||||
|
||||
<!-- ============ STEP 3: Org Tenant ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="392" y="150" width="470" height="600" rx="16" fill="#ffffff" stroke="#cdd3df" stroke-width="1.5"/>
|
||||
</g>
|
||||
<circle cx="418" cy="178" r="13" fill="#0f172a"/><text x="418" y="183" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">3</text>
|
||||
<text x="442" y="183" font-size="15" font-weight="700" fill="#0f172a">Org Tenant — isolated EC2 · Postgres · Redis</text>
|
||||
|
||||
<!-- PM -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="556" y="206" width="142" height="58" rx="10" fill="#0f172a"/>
|
||||
</g>
|
||||
<text x="627" y="231" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">Marketing PM</text>
|
||||
<text x="627" y="250" font-size="11.5" fill="#cbd5e1" text-anchor="middle">coordinator</text>
|
||||
|
||||
<!-- children -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="414" y="300" width="140" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="562" y="300" width="140" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="710" y="300" width="138" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
</g>
|
||||
<text x="484" y="326" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Research</text>
|
||||
<text x="484" y="344" font-size="10.5" fill="#5b6472" text-anchor="middle">trends · audience</text>
|
||||
<text x="632" y="326" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Content Writer</text>
|
||||
<text x="632" y="344" font-size="10.5" fill="#5b6472" text-anchor="middle">drafts · creative</text>
|
||||
<text x="779" y="326" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Reviewer</text>
|
||||
<text x="779" y="344" font-size="10.5" fill="#5b6472" text-anchor="middle">brand · compliance</text>
|
||||
|
||||
<!-- PM -> children connectors -->
|
||||
<g stroke="#94a3b8" stroke-width="1.4" fill="none">
|
||||
<path d="M627,264 L627,284 L484,284 L484,300" marker-end="url(#arrow)"/>
|
||||
<path d="M627,284 L632,284 L632,300" marker-end="url(#arrow)"/>
|
||||
<path d="M627,284 L779,284 L779,300" marker-end="url(#arrow)"/>
|
||||
</g>
|
||||
<text x="627" y="280" font-size="10.5" fill="#64748b" text-anchor="middle">delegates over A2A</text>
|
||||
|
||||
<!-- Governance band -->
|
||||
<rect x="414" y="392" width="434" height="86" rx="12" fill="#ecfdf5" stroke="#10b981" stroke-width="1.5"/>
|
||||
<text x="432" y="416" font-size="14" font-weight="700" fill="#047857">Governance Layer · what raw A2A omits</text>
|
||||
<text x="432" y="438" font-size="12" fill="#0f766e">discovery / registry · access-control (who-may-call-whom)</text>
|
||||
<text x="432" y="456" font-size="12" fill="#0f766e">hierarchical shared memory · human-approval gates</text>
|
||||
<text x="432" y="472" font-size="12" fill="#0f766e">A2A routing · OTEL · compliance hooks</text>
|
||||
|
||||
<!-- MCP band -->
|
||||
<rect x="414" y="500" width="434" height="74" rx="12" fill="#faf5ff" stroke="#9333ea" stroke-width="1.5"/>
|
||||
<text x="432" y="524" font-size="14" font-weight="700" fill="#7c3aed">a2a_mcp_server (MCP)</text>
|
||||
<text x="432" y="545" font-size="12" fill="#6d28d9">platform tools: filesystem · shell · web · peer messaging</text>
|
||||
<text x="432" y="562" font-size="12" fill="#6d28d9">the “securely connect to external tools via MCP” pattern</text>
|
||||
|
||||
<!-- agents run on ADK note -->
|
||||
<text x="627" y="606" font-size="11.5" fill="#64748b" text-anchor="middle" font-style="italic">each agent runs a per-agent ADK runtime ▸</text>
|
||||
|
||||
<!-- ============ STEP 4: ADK runtime ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="906" y="206" width="276" height="300" rx="14" fill="#f8fafc" stroke="#0ea5e9" stroke-width="1.5"/>
|
||||
</g>
|
||||
<circle cx="932" cy="232" r="13" fill="#0ea5e9"/><text x="932" y="237" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">4</text>
|
||||
<text x="956" y="231" font-size="14.5" font-weight="700" fill="#0369a1">Per-agent ADK runtime</text>
|
||||
<text x="926" y="252" font-size="11.5" fill="#5b6472">google-adk[mcp] 2.1.0</text>
|
||||
|
||||
<rect x="926" y="266" width="236" height="56" rx="9" fill="#ffffff" stroke="#bae6fd"/>
|
||||
<text x="940" y="290" font-size="13.5" font-weight="600" fill="#15181f">LlmAgent + Runner</text>
|
||||
<text x="940" y="309" font-size="11.5" fill="#5b6472">the ADK agent engine</text>
|
||||
|
||||
<rect x="926" y="332" width="236" height="76" rx="9" fill="#fff7ed" stroke="#f4c98a"/>
|
||||
<text x="940" y="356" font-size="13.5" font-weight="600" fill="#b45309">Molecule A2A Executor</text>
|
||||
<text x="940" y="375" font-size="11.5" fill="#92560a">Runner events → a2a-1.x</text>
|
||||
<text x="940" y="391" font-size="11.5" fill="#92560a">EventQueue / TaskUpdater · heartbeat</text>
|
||||
|
||||
<rect x="926" y="418" width="236" height="56" rx="9" fill="#ffffff" stroke="#e9d5ff"/>
|
||||
<text x="940" y="442" font-size="13.5" font-weight="600" fill="#7c3aed">McpToolset</text>
|
||||
<text x="940" y="461" font-size="11.5" fill="#6d28d9">native ADK → platform MCP tools</text>
|
||||
|
||||
<!-- ============ STEP 5: Google Cloud keyless chain ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="1206" y="206" width="226" height="544" rx="14" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.5"/>
|
||||
</g>
|
||||
<circle cx="1232" cy="232" r="13" fill="#4285f4"/><text x="1232" y="237" font-size="14" font-weight="700" fill="#fff" text-anchor="middle">5</text>
|
||||
<text x="1256" y="237" font-size="14.5" font-weight="700" fill="#1a56c4">Google Cloud</text>
|
||||
|
||||
<rect x="1226" y="268" width="186" height="78" rx="10" fill="#ffffff" stroke="#9cc0fb"/>
|
||||
<text x="1240" y="292" font-size="13" font-weight="700" fill="#1a73e8">GCP STS</text>
|
||||
<text x="1240" y="311" font-size="11.5" fill="#3b6fd4">Workload Identity</text>
|
||||
<text x="1240" y="327" font-size="11.5" fill="#3b6fd4">Federation (WIF)</text>
|
||||
<text x="1240" y="343" font-size="10.5" fill="#7c8aa3">AWS EC2 role → aws_role</text>
|
||||
|
||||
<rect x="1226" y="372" width="186" height="84" rx="10" fill="#ffffff" stroke="#9cc0fb"/>
|
||||
<text x="1240" y="396" font-size="13" font-weight="700" fill="#1a73e8">Service Account</text>
|
||||
<text x="1240" y="415" font-size="11" fill="#3b6fd4">molecule-vertex-adc@</text>
|
||||
<text x="1240" y="431" font-size="11" fill="#3b6fd4">roles/aiplatform.user</text>
|
||||
<text x="1240" y="448" font-size="10.5" fill="#7c8aa3">least-privilege · impersonated</text>
|
||||
|
||||
<rect x="1226" y="482" width="186" height="84" rx="10" fill="#ffffff" stroke="#4285f4" stroke-width="2"/>
|
||||
<text x="1240" y="508" font-size="13.5" font-weight="700" fill="#1a56c4">Vertex AI</text>
|
||||
<text x="1240" y="529" font-size="13" font-weight="700" fill="#15181f">gemini-2.5-pro</text>
|
||||
<text x="1240" y="549" font-size="11" fill="#7c8aa3">no key — short-lived token only</text>
|
||||
|
||||
<!-- keyless chain inside GCP -->
|
||||
<g stroke="#d97706" stroke-width="1.8" fill="none" stroke-dasharray="6 4">
|
||||
<path d="M1319,346 L1319,372" marker-end="url(#arrowGold)"/>
|
||||
<path d="M1319,456 L1319,482" marker-end="url(#arrowGold)"/>
|
||||
</g>
|
||||
<text x="1326" y="364" font-size="10" fill="#b45309">federate</text>
|
||||
<text x="1326" y="474" font-size="10" fill="#b45309">short-lived token</text>
|
||||
|
||||
<!-- ============ cross-zone arrows ============ -->
|
||||
<!-- Canvas -> Provisioner -->
|
||||
<path d="M198,270 L198,362" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#arrow)"/>
|
||||
<text x="206" y="300" font-size="11.5" fill="#475569">org.yaml</text>
|
||||
<!-- SSOT -> Provisioner (internal, implied by stacking) -->
|
||||
<path d="M198,434 L198,426" stroke="#94a3b8" stroke-width="1.4" fill="none" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- Provisioner -> Tenant -->
|
||||
<path d="M348,400 C372,400 372,300 392,300" stroke="#4f46e5" stroke-width="1.8" fill="none" marker-end="url(#arrow)"/>
|
||||
<text x="356" y="345" font-size="11.5" font-weight="600" fill="#4338ca">provision</text>
|
||||
<text x="356" y="360" font-size="11.5" font-weight="600" fill="#4338ca">tenant + agents</text>
|
||||
|
||||
<!-- Governance -> ADK runtime -->
|
||||
<path d="M848,420 C878,420 878,300 906,300" stroke="#0ea5e9" stroke-width="1.8" fill="none" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- McpToolset .- MCP (dashed) -->
|
||||
<path d="M926,446 C886,470 886,536 848,536" stroke="#9333ea" stroke-width="1.6" fill="none" stroke-dasharray="6 4" marker-end="url(#arrow)" marker-start="url(#arrow)"/>
|
||||
<text x="858" y="500" font-size="10.5" font-weight="600" fill="#7c3aed">MCP</text>
|
||||
|
||||
<!-- Executor -> STS (keyless, gold) -->
|
||||
<path d="M1162,372 C1190,372 1198,300 1226,300" stroke="#d97706" stroke-width="2" fill="none" stroke-dasharray="6 4" marker-end="url(#arrowGold)"/>
|
||||
<text x="1170" y="356" font-size="10" font-weight="700" fill="#b45309">ADC · no key</text>
|
||||
|
||||
<!-- LlmAgent -> Vertex (inference, blue) -->
|
||||
<path d="M1162,290 C1186,290 1196,520 1226,520" stroke="#1a73e8" stroke-width="2" fill="none" marker-end="url(#arrowBlue)"/>
|
||||
<text x="1150" y="640" font-size="10.5" font-weight="600" fill="#1a56c4" text-anchor="end">inference (Gemini)</text>
|
||||
|
||||
<!-- ============ footer / proof ============ -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="48" y="788" width="1384" height="150" rx="14" fill="#ffffff" stroke="#cdd3df" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="68" y="820" font-size="15" font-weight="700" fill="#15181f">Live & verified in production</text>
|
||||
<text x="68" y="848" font-size="13" fill="#374151"><tspan font-weight="600" fill="#1a73e8">molecule-adk-demo.moleculesai.app</tspan> — 4 agents · runtime <tspan font-family="monospace" fill="#b45309">google-adk</tspan> · model <tspan font-family="monospace" fill="#b45309">vertex:gemini-2.5-pro</tspan> · keyless (no GOOGLE_API_KEY)</text>
|
||||
<text x="68" y="874" font-size="12.5" fill="#5b6472">Per-(provider×auth) serving E2E gate · provisioning fails loud on runtime/config mismatch · 100% unit coverage on the ADC path + a real no-key Gemini-on-Vertex E2E.</text>
|
||||
|
||||
<!-- legend -->
|
||||
<g font-size="11.5">
|
||||
<rect x="68" y="892" width="14" height="14" rx="3" fill="#fff7ed" stroke="#f59e0b"/><text x="90" y="903" fill="#5b6472">keyless credential chain (WIF/ADC)</text>
|
||||
<rect x="320" y="892" width="14" height="14" rx="3" fill="#ecfdf5" stroke="#10b981"/><text x="342" y="903" fill="#5b6472">governance layer</text>
|
||||
<rect x="500" y="892" width="14" height="14" rx="3" fill="#faf5ff" stroke="#9333ea"/><text x="522" y="903" fill="#5b6472">MCP tools</text>
|
||||
<rect x="640" y="892" width="14" height="14" rx="3" fill="#e8f0fe" stroke="#4285f4"/><text x="662" y="903" fill="#5b6472">Google Cloud (Vertex AI)</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,54 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 560" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="ain" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#4f46e5"/></marker>
|
||||
<marker id="aout" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="560" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Channels — chat in, agent out</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">External chat platforms bridge to a workspace over A2A. Inbound is allowlist-gated; outbound replies route back through the same adapter.</text>
|
||||
|
||||
<!-- platforms -->
|
||||
<g filter="url(#sh)"><rect x="40" y="150" width="210" height="260" rx="13" fill="#ffffff" stroke="#cdd3df" stroke-width="1.5"/></g>
|
||||
<text x="145" y="178" font-size="13.5" font-weight="700" fill="#15181f" text-anchor="middle">Chat platform</text>
|
||||
<g font-size="12" text-anchor="middle">
|
||||
<rect x="62" y="196" width="166" height="40" rx="8" fill="#f8fafc" stroke="#cbd5e1"/><text x="145" y="214" font-weight="600" fill="#15181f">Telegram</text><text x="145" y="229" font-size="9.5" fill="#5b6472">long-poll / webhook</text>
|
||||
<rect x="62" y="244" width="166" height="40" rx="8" fill="#f8fafc" stroke="#cbd5e1"/><text x="145" y="262" font-weight="600" fill="#15181f">Slack</text><text x="145" y="277" font-size="9.5" fill="#5b6472">Events API</text>
|
||||
<rect x="62" y="292" width="166" height="40" rx="8" fill="#f8fafc" stroke="#cbd5e1"/><text x="145" y="310" font-weight="600" fill="#15181f">Discord</text><text x="145" y="325" font-size="9.5" fill="#5b6472">Interactions (no poll)</text>
|
||||
<rect x="62" y="340" width="166" height="40" rx="8" fill="#f8fafc" stroke="#cbd5e1"/><text x="145" y="358" font-weight="600" fill="#15181f">Lark / Feishu</text><text x="145" y="373" font-size="9.5" fill="#5b6472">Event Subscriptions</text>
|
||||
</g>
|
||||
|
||||
<!-- platform adapter -->
|
||||
<g filter="url(#sh)"><rect x="430" y="150" width="330" height="260" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="595" y="178" font-size="14" font-weight="700" fill="#3730a3" text-anchor="middle">Control Plane · channel adapter</text>
|
||||
<g font-size="12" fill="#15181f">
|
||||
<rect x="452" y="196" width="286" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="466" y="219" font-weight="600">POST /webhooks/:type</text>
|
||||
<rect x="452" y="242" width="286" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="466" y="265">adapter.ParseWebhook → normalize</text>
|
||||
<rect x="452" y="288" width="286" height="38" rx="8" fill="#fff7ed" stroke="#f4c98a"/><text x="466" y="311" fill="#b45309">allowlist gate (chat_id / user)</text>
|
||||
<rect x="452" y="334" width="286" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="466" y="357">A2A message/send → target workspace</text>
|
||||
</g>
|
||||
|
||||
<!-- workspace -->
|
||||
<g filter="url(#sh)"><rect x="940" y="206" width="220" height="148" rx="13" fill="#ffffff" stroke="#5b5bd6" stroke-width="1.5"/></g>
|
||||
<text x="1050" y="252" font-size="14" font-weight="700" fill="#15181f" text-anchor="middle">Workspace agent</text>
|
||||
<text x="1050" y="276" font-size="11" fill="#5b6472" text-anchor="middle">runs the turn, replies</text>
|
||||
<text x="1050" y="300" font-size="10.5" fill="#7c6df2" text-anchor="middle">caller = channel:<type></text>
|
||||
|
||||
<!-- inbound arrows -->
|
||||
<path d="M250,250 L430,225" stroke="#4f46e5" stroke-width="1.8" fill="none" marker-end="url(#ain)"/>
|
||||
<text x="300" y="220" font-size="11" font-weight="700" fill="#4338ca">① user message</text>
|
||||
<path d="M760,265 L940,265" stroke="#4f46e5" stroke-width="1.8" fill="none" marker-end="url(#ain)"/>
|
||||
<text x="850" y="256" font-size="10.5" fill="#4338ca">② A2A in</text>
|
||||
|
||||
<!-- outbound arrows -->
|
||||
<path d="M940,310 L760,330" stroke="#10b981" stroke-width="1.8" fill="none" marker-end="url(#aout)"/>
|
||||
<text x="828" y="345" font-size="10.5" fill="#047857">③ reply</text>
|
||||
<path d="M430,360 L250,335" stroke="#10b981" stroke-width="1.8" fill="none" marker-end="url(#aout)"/>
|
||||
<text x="300" y="372" font-size="11" font-weight="700" fill="#047857">④ back to user</text>
|
||||
|
||||
<!-- notes -->
|
||||
<rect x="40" y="446" width="1120" height="86" rx="11" fill="#f8fafc" stroke="#cdd3df"/>
|
||||
<text x="60" y="472" font-size="12.5" font-weight="700" fill="#15181f">Config & safety</text>
|
||||
<text x="60" y="494" font-size="11.5" fill="#475569">• Tokens/webhook secrets are encrypted at rest and masked on read. • Inbound is gated by an allowlist (chat id / user) before any A2A call.</text>
|
||||
<text x="60" y="514" font-size="11.5" fill="#475569">• Each channel binds to a workspace; the agent sees the sender as <tspan font-family="monospace" fill="#4f46e5">channel:<type></tspan> and replies through the same adapter (round-trip).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,141 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 760" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
<marker id="ai" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#4f46e5"/></marker>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
<marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#ef4444"/></marker>
|
||||
</defs>
|
||||
<rect width="1280" height="760" fill="#fbfcfe"/>
|
||||
<text x="44" y="50" font-size="27" font-weight="700" fill="#15181f">Molecule AI — Core Concepts</text>
|
||||
<text x="44" y="78" font-size="14.5" fill="#5b6472">Run a multi-agent <tspan font-weight="700" fill="#4f46e5">organization</tspan> as code: one <tspan font-family="monospace" fill="#b45309">org.yaml</tspan> → a tree of agent <tspan font-weight="600">Workspaces</tspan> that talk peer-to-peer over A2A, governed by the org hierarchy.</text>
|
||||
|
||||
<!-- Operator + Canvas -->
|
||||
<g filter="url(#sh)"><rect x="44" y="110" width="250" height="92" rx="13" fill="#f6f4ff" stroke="#7c6df2" stroke-width="1.5"/></g>
|
||||
<text x="64" y="138" font-size="14.5" font-weight="700" fill="#3b2fae">Canvas (operator UI)</text>
|
||||
<text x="64" y="160" font-size="12" fill="#5b6472">Next.js · React Flow org-chart</text>
|
||||
<text x="64" y="178" font-size="12" fill="#5b6472">live nodes · drag/create · approvals</text>
|
||||
<text x="64" y="195" font-size="11.5" fill="#7c6df2">app.moleculesai.app</text>
|
||||
|
||||
<!-- org.yaml -->
|
||||
<g filter="url(#sh)"><rect x="44" y="232" width="250" height="92" rx="13" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.5"/></g>
|
||||
<text x="64" y="260" font-size="14.5" font-weight="700" fill="#b45309">org.yaml — declarative intent</text>
|
||||
<text x="64" y="282" font-size="12" fill="#92560a">org tree · roles · runtime · tier</text>
|
||||
<text x="64" y="300" font-size="12" fill="#92560a">model · plugins · schedules · channels</text>
|
||||
<text x="64" y="317" font-size="11.5" fill="#b45309">imported once → provisions the org</text>
|
||||
|
||||
<!-- Marketplace -->
|
||||
<g filter="url(#sh)"><rect x="44" y="354" width="250" height="84" rx="13" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/></g>
|
||||
<text x="64" y="382" font-size="14.5" font-weight="700" fill="#15181f">Marketplace</text>
|
||||
<text x="64" y="404" font-size="12" fill="#5b6472">L1 Plugins · L2 Agents · L3 Bundles</text>
|
||||
<text x="64" y="422" font-size="12" fill="#5b6472">install → adds capability to a workspace</text>
|
||||
|
||||
<!-- Control Plane -->
|
||||
<g filter="url(#sh)"><rect x="372" y="120" width="300" height="360" rx="16" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="392" y="150" font-size="16" font-weight="700" fill="#3730a3">Control Plane · Platform</text>
|
||||
<text x="392" y="170" font-size="12" fill="#6366f1">Go / Gin · :8080</text>
|
||||
<g font-size="12.5" fill="#15181f">
|
||||
<rect x="392" y="184" width="260" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="406" y="204">provisioner — spawns workspace containers</text>
|
||||
<rect x="392" y="220" width="260" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="406" y="240">registry + discovery — who/where (ACL gate)</text>
|
||||
<rect x="392" y="256" width="260" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="406" y="276">A2A proxy (canvas) · WebSocket event hub</text>
|
||||
<rect x="392" y="292" width="260" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="406" y="312">scheduler · channels · secrets · budget</text>
|
||||
</g>
|
||||
<!-- datastores -->
|
||||
<g filter="url(#sh)"><rect x="392" y="336" width="125" height="64" rx="10" fill="#ffffff" stroke="#94a3b8"/></g>
|
||||
<text x="454" y="362" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Postgres</text>
|
||||
<text x="454" y="381" font-size="10.5" fill="#5b6472" text-anchor="middle">source of truth</text>
|
||||
<text x="454" y="394" font-size="10.5" fill="#5b6472" text-anchor="middle">event-sourced</text>
|
||||
<g filter="url(#sh)"><rect x="527" y="336" width="125" height="64" rx="10" fill="#ffffff" stroke="#94a3b8"/></g>
|
||||
<text x="589" y="362" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Redis</text>
|
||||
<text x="589" y="381" font-size="10.5" fill="#5b6472" text-anchor="middle">liveness TTL</text>
|
||||
<text x="589" y="394" font-size="10.5" fill="#5b6472" text-anchor="middle">pub/sub</text>
|
||||
<text x="392" y="430" font-size="11" fill="#6366f1">platform is in the discovery path —</text>
|
||||
<text x="392" y="446" font-size="11" fill="#6366f1">NOT in the agent↔agent data path.</text>
|
||||
<text x="392" y="466" font-size="11" fill="#6366f1">one org = one isolated Tenant (EC2 · PG · Redis).</text>
|
||||
|
||||
<!-- Tenant: org tree -->
|
||||
<g filter="url(#sh)"><rect x="720" y="120" width="516" height="500" rx="16" fill="#ffffff" stroke="#cdd3df" stroke-width="1.6"/></g>
|
||||
<text x="742" y="150" font-size="16" font-weight="700" fill="#0f172a">Org Tenant — Workspaces (one agent each)</text>
|
||||
<text x="742" y="170" font-size="12" fill="#64748b">isolated container per workspace · per-workspace bearer token · pluggable runtime</text>
|
||||
|
||||
<!-- root -->
|
||||
<g filter="url(#sh)"><rect x="906" y="196" width="150" height="54" rx="10" fill="#0f172a"/></g>
|
||||
<text x="981" y="219" font-size="13.5" font-weight="700" fill="#fff" text-anchor="middle">Org Lead</text>
|
||||
<text x="981" y="238" font-size="10.5" fill="#cbd5e1" text-anchor="middle">root workspace</text>
|
||||
<!-- children -->
|
||||
<g filter="url(#sh)">
|
||||
<rect x="760" y="300" width="150" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="930" y="300" width="150" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="1086" y="300" width="132" height="58" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
</g>
|
||||
<text x="835" y="324" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Agent A</text>
|
||||
<text x="835" y="343" font-size="10.5" fill="#5b6472" text-anchor="middle">runtime · tier · skills</text>
|
||||
<text x="1005" y="324" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Team Lead B</text>
|
||||
<text x="1005" y="343" font-size="10.5" fill="#5b6472" text-anchor="middle">coordinator</text>
|
||||
<text x="1152" y="324" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Agent C</text>
|
||||
<text x="1152" y="343" font-size="10.5" fill="#5b6472" text-anchor="middle">specialist</text>
|
||||
<!-- grandchildren under B -->
|
||||
<g filter="url(#sh)">
|
||||
<rect x="930" y="404" width="120" height="50" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
<rect x="1062" y="404" width="120" height="50" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
</g>
|
||||
<text x="990" y="426" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">Agent B1</text>
|
||||
<text x="990" y="442" font-size="10" fill="#5b6472" text-anchor="middle">sub-agent</text>
|
||||
<text x="1122" y="426" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">Agent B2</text>
|
||||
<text x="1122" y="442" font-size="10" fill="#5b6472" text-anchor="middle">sub-agent</text>
|
||||
|
||||
<!-- hierarchy connectors (structure) -->
|
||||
<g stroke="#94a3b8" stroke-width="1.4" fill="none">
|
||||
<path d="M981,250 L981,276 L835,276 L835,300"/>
|
||||
<path d="M981,276 L1005,276 L1005,300"/>
|
||||
<path d="M981,276 L1152,276 L1152,300"/>
|
||||
<path d="M1005,358 L1005,380 L990,380 L990,404"/>
|
||||
<path d="M1005,380 L1122,380 L1122,404"/>
|
||||
</g>
|
||||
|
||||
<!-- A2A allowed (green) and denied (red) -->
|
||||
<path d="M910,329 L930,329" stroke="#10b981" stroke-width="2.2" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M990,454 C990,478 1122,478 1122,454" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M835,358 C835,392 990,392 990,404" stroke="#ef4444" stroke-width="1.8" fill="none" stroke-dasharray="5 4" marker-end="url(#ar)"/>
|
||||
<text x="912" y="498" font-size="11" fill="#047857">A2A allowed: siblings · parent ↔ child</text>
|
||||
<text x="760" y="498" font-size="11" fill="#dc2626">✕ skip-level / cross-team denied</text>
|
||||
<text x="742" y="556" font-size="12" fill="#334155">The org chart <tspan font-weight="700">is</tspan> the access-control policy — comms, memory scope & event fan-out</text>
|
||||
<text x="742" y="574" font-size="12" fill="#334155">all derive from <tspan font-family="monospace" fill="#4f46e5">parent_id</tspan>. No edges to wire by hand.</text>
|
||||
<!-- governance chip -->
|
||||
<rect x="742" y="590" width="220" height="22" rx="11" fill="#ecfdf5" stroke="#10b981"/>
|
||||
<text x="752" y="605" font-size="11" font-weight="700" fill="#047857">Governance layer mediates every hop</text>
|
||||
|
||||
<!-- External agent -->
|
||||
<g filter="url(#sh)"><rect x="372" y="520" width="300" height="100" rx="13" fill="#faf5ff" stroke="#9333ea" stroke-width="1.5"/></g>
|
||||
<text x="392" y="548" font-size="14.5" font-weight="700" fill="#7c3aed">External / Remote agent</text>
|
||||
<text x="392" y="570" font-size="12" fill="#6d28d9">runtime: external — your infra, any A2A/MCP agent</text>
|
||||
<text x="392" y="588" font-size="12" fill="#6d28d9">register + 30s heartbeat → joins the same canvas</text>
|
||||
<text x="392" y="606" font-size="11.5" fill="#9333ea">REMOTE badge · pulls secrets on demand</text>
|
||||
|
||||
<!-- ====== cross arrows ====== -->
|
||||
<!-- org.yaml -> CP import -->
|
||||
<path d="M294,278 C334,278 340,250 372,250" stroke="#f59e0b" stroke-width="1.8" fill="none" marker-end="url(#a)"/>
|
||||
<text x="300" y="244" font-size="11" font-weight="600" fill="#b45309">import</text>
|
||||
<!-- Canvas <-> CP -->
|
||||
<path d="M294,150 L372,160" stroke="#4f46e5" stroke-width="1.6" fill="none" marker-end="url(#ai)" marker-start="url(#ai)"/>
|
||||
<text x="300" y="138" font-size="10.5" fill="#4338ca">REST · WebSocket</text>
|
||||
<!-- Marketplace -> tenant workspace -->
|
||||
<path d="M294,396 C330,396 690,360 720,340" stroke="#64748b" stroke-width="1.5" fill="none" marker-end="url(#a)"/>
|
||||
<text x="300" y="414" font-size="10.5" fill="#475569">install → workspace</text>
|
||||
<!-- CP -> Tenant provision -->
|
||||
<path d="M672,250 C696,250 696,300 720,300" stroke="#4f46e5" stroke-width="2" fill="none" marker-end="url(#ai)"/>
|
||||
<text x="676" y="276" font-size="11.5" font-weight="700" fill="#4338ca">provision</text>
|
||||
<!-- CP -> Canvas events (WS) -->
|
||||
<path d="M520,184 C520,176 360,176 294,176" stroke="#4f46e5" stroke-width="1.5" fill="none" stroke-dasharray="5 4" marker-end="url(#ai)"/>
|
||||
<!-- External <-> CP -->
|
||||
<path d="M522,520 L522,484" stroke="#9333ea" stroke-width="1.7" fill="none" marker-end="url(#ai)" marker-start="url(#ai)"/>
|
||||
<text x="528" y="508" font-size="10.5" fill="#7c3aed">register · heartbeat · A2A</text>
|
||||
|
||||
<!-- legend -->
|
||||
<g font-size="11">
|
||||
<line x1="44" y1="648" x2="72" y2="648" stroke="#10b981" stroke-width="2.2"/><text x="80" y="652" fill="#5b6472">A2A allowed</text>
|
||||
<line x1="200" y1="648" x2="228" y2="648" stroke="#ef4444" stroke-width="1.8" stroke-dasharray="5 4"/><text x="236" y="652" fill="#5b6472">denied by hierarchy</text>
|
||||
<line x1="396" y1="648" x2="424" y2="648" stroke="#4f46e5" stroke-width="1.6"/><text x="432" y="652" fill="#5b6472">control-plane (REST/WS/provision)</text>
|
||||
<line x1="700" y1="648" x2="728" y2="648" stroke="#f59e0b" stroke-width="1.8"/><text x="736" y="652" fill="#5b6472">declarative import</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,81 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 600" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
<marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#ef4444"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="600" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Governance — the org chart is the access-control policy</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472"><tspan font-family="monospace" fill="#4f46e5">CanCommunicate(caller, target)</tspan> permits self · siblings · parent↔child, and denies everything else. The same hierarchy scopes memory and event fan-out.</text>
|
||||
|
||||
<!-- tree -->
|
||||
<g filter="url(#sh)"><rect x="500" y="108" width="200" height="52" rx="10" fill="#0f172a"/></g>
|
||||
<text x="600" y="139" font-size="13" font-weight="700" fill="#fff" text-anchor="middle">Org Lead (root)</text>
|
||||
|
||||
<g filter="url(#sh)">
|
||||
<rect x="250" y="210" width="190" height="52" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="760" y="210" width="190" height="52" rx="10" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
</g>
|
||||
<text x="345" y="241" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Team A lead</text>
|
||||
<text x="855" y="241" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Team B lead</text>
|
||||
|
||||
<g filter="url(#sh)">
|
||||
<rect x="150" y="312" width="170" height="48" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
<rect x="350" y="312" width="170" height="48" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
<rect x="700" y="312" width="170" height="48" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
<rect x="900" y="312" width="170" height="48" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.2"/>
|
||||
</g>
|
||||
<text x="235" y="341" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">A1</text>
|
||||
<text x="435" y="341" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">A2</text>
|
||||
<text x="785" y="341" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">B1</text>
|
||||
<text x="985" y="341" font-size="11.5" font-weight="600" fill="#15181f" text-anchor="middle">B2</text>
|
||||
|
||||
<!-- structure -->
|
||||
<g stroke="#94a3b8" stroke-width="1.4" fill="none">
|
||||
<path d="M600,160 L600,186 L345,186 L345,210"/>
|
||||
<path d="M600,186 L855,186 L855,210"/>
|
||||
<path d="M345,262 L345,288 L235,288 L235,312"/>
|
||||
<path d="M345,288 L435,288 L435,312"/>
|
||||
<path d="M855,262 L855,288 L785,288 L785,312"/>
|
||||
<path d="M855,288 L985,288 L985,312"/>
|
||||
</g>
|
||||
|
||||
<!-- allowed: parent<->child, siblings -->
|
||||
<path d="M320,336 L350,336" stroke="#10b981" stroke-width="2.2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M870,336 L900,336" stroke="#10b981" stroke-width="2.2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M345,262 L300,312" stroke="#10b981" stroke-width="1.8" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M440,236 L760,236" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<text x="600" y="228" font-size="10.5" fill="#047857" text-anchor="middle">siblings (root-level) ✓</text>
|
||||
|
||||
<!-- denied: skip-level + cross-team -->
|
||||
<path d="M235,312 C235,250 560,150 600,160" stroke="#ef4444" stroke-width="1.6" fill="none" stroke-dasharray="5 4" marker-end="url(#ar)"/>
|
||||
<text x="300" y="200" font-size="10.5" fill="#dc2626">✕ skip-level (A1 → root)</text>
|
||||
<path d="M435,348 C600,420 700,420 785,360" stroke="#ef4444" stroke-width="1.6" fill="none" stroke-dasharray="5 4" marker-end="url(#ar)"/>
|
||||
<text x="600" y="430" font-size="10.5" fill="#dc2626" text-anchor="middle">✕ cross-team (A2 → B1)</text>
|
||||
|
||||
<!-- trust boundary callout -->
|
||||
<rect x="40" y="404" width="360" height="166" rx="11" fill="#ecfdf5" stroke="#10b981" stroke-width="1.4"/>
|
||||
<text x="60" y="430" font-size="13" font-weight="700" fill="#047857">Allowed (CanCommunicate ✓)</text>
|
||||
<text x="60" y="452" font-size="11.5" fill="#0f766e">• self • siblings (same parent / both root)</text>
|
||||
<text x="60" y="470" font-size="11.5" fill="#0f766e">• parent → child • child → parent</text>
|
||||
<text x="60" y="494" font-size="13" font-weight="700" fill="#b91c1c">Denied (403)</text>
|
||||
<text x="60" y="516" font-size="11.5" fill="#7f1d1d">• skip-level (grandparent/grandchild)</text>
|
||||
<text x="60" y="534" font-size="11.5" fill="#7f1d1d">• cross-team (different subtree)</text>
|
||||
<text x="60" y="556" font-size="10.5" fill="#475569">canvas + system:* / webhook:* are explicit bypass callers</text>
|
||||
|
||||
<rect x="420" y="404" width="360" height="166" rx="11" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.4"/>
|
||||
<text x="440" y="430" font-size="13" font-weight="700" fill="#3730a3">Same hierarchy governs</text>
|
||||
<text x="440" y="454" font-size="11.5" fill="#4338ca">• A2A — who may message whom</text>
|
||||
<text x="440" y="474" font-size="11.5" fill="#4338ca">• Memory — LOCAL / TEAM / GLOBAL reach</text>
|
||||
<text x="440" y="494" font-size="11.5" fill="#4338ca">• Events — WebSocket fan-out is ACL-filtered</text>
|
||||
<text x="440" y="514" font-size="11.5" fill="#4338ca">• Peer discovery — reachable set only</text>
|
||||
<text x="440" y="538" font-size="10.5" fill="#6366f1">one rule, enforced at the A2A proxy + registry</text>
|
||||
|
||||
<rect x="800" y="404" width="360" height="166" rx="11" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.4"/>
|
||||
<text x="820" y="430" font-size="13" font-weight="700" fill="#b45309">Isolation underneath</text>
|
||||
<text x="820" y="454" font-size="11.5" fill="#92560a">• each workspace = its own machine</text>
|
||||
<text x="820" y="474" font-size="11.5" fill="#92560a">• no shared filesystem / env / secrets</text>
|
||||
<text x="820" y="494" font-size="11.5" fill="#92560a">• A2A over the network is the only path</text>
|
||||
<text x="820" y="514" font-size="11.5" fill="#92560a">• per-workspace bearer token + encrypted secrets</text>
|
||||
<text x="820" y="538" font-size="10.5" fill="#b45309">defense in depth: ACL above, machine isolation below</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,64 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1120 540" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
</defs>
|
||||
<rect width="1120" height="540" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Hermes — multi-provider dispatch</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">One runtime, many providers. Hermes routes by which API key is present, into the right protocol — fail-loud if the SDK is missing.</text>
|
||||
|
||||
<!-- key priority resolver -->
|
||||
<g filter="url(#sh)"><rect x="40" y="120" width="300" height="300" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="190" y="148" font-size="14" font-weight="700" fill="#3730a3" text-anchor="middle">Key-priority resolver</text>
|
||||
<text x="190" y="168" font-size="11" fill="#6366f1" text-anchor="middle">first key present wins</text>
|
||||
<g font-size="12" font-family="monospace">
|
||||
<rect x="62" y="184" width="256" height="34" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="76" y="206" fill="#15181f">1 · HERMES_API_KEY</text>
|
||||
<rect x="62" y="226" width="256" height="34" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="76" y="248" fill="#15181f">2 · OPENROUTER_API_KEY</text>
|
||||
<rect x="62" y="268" width="256" height="34" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="76" y="290" fill="#15181f">3 · ANTHROPIC_API_KEY</text>
|
||||
<rect x="62" y="310" width="256" height="34" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="76" y="332" fill="#15181f">4 · GEMINI_API_KEY</text>
|
||||
</g>
|
||||
<text x="190" y="372" font-size="11" fill="#6366f1" text-anchor="middle">workspace secrets → resolver</text>
|
||||
<text x="190" y="392" font-size="11" fill="#6366f1" text-anchor="middle">picks transport for the model id</text>
|
||||
|
||||
<!-- transports -->
|
||||
<g filter="url(#sh)">
|
||||
<rect x="430" y="130" width="290" height="84" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
<rect x="430" y="228" width="290" height="84" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
<rect x="430" y="326" width="290" height="84" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
</g>
|
||||
<text x="448" y="158" font-size="13" font-weight="700" fill="#15181f">Native Anthropic</text>
|
||||
<text x="448" y="180" font-size="11" fill="#5b6472">/v1/messages — Claude</text>
|
||||
<text x="448" y="200" font-size="10.5" fill="#94a3b8" font-family="monospace">anthropic SDK</text>
|
||||
<text x="448" y="256" font-size="13" font-weight="700" fill="#15181f">Native Gemini</text>
|
||||
<text x="448" y="278" font-size="11" fill="#5b6472">generateContent — Gemini</text>
|
||||
<text x="448" y="298" font-size="10.5" fill="#94a3b8" font-family="monospace">google-genai SDK</text>
|
||||
<text x="448" y="354" font-size="13" font-weight="700" fill="#15181f">OpenAI-compatible shim</text>
|
||||
<text x="448" y="376" font-size="11" fill="#5b6472">/chat/completions — 13+ providers</text>
|
||||
<text x="448" y="396" font-size="10.5" fill="#94a3b8" font-family="monospace">OpenRouter · DeepSeek · …</text>
|
||||
|
||||
<g stroke="#64748b" stroke-width="1.5" fill="none">
|
||||
<path d="M340,260 C385,200 390,172 430,172" marker-end="url(#a)"/>
|
||||
<path d="M340,270 L430,270" marker-end="url(#a)"/>
|
||||
<path d="M340,280 C385,340 390,368 430,368" marker-end="url(#a)"/>
|
||||
</g>
|
||||
|
||||
<!-- providers -->
|
||||
<g filter="url(#sh)"><rect x="800" y="130" width="280" height="280" rx="13" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.5"/></g>
|
||||
<text x="940" y="158" font-size="13.5" font-weight="700" fill="#1a56c4" text-anchor="middle">Providers reached</text>
|
||||
<g font-size="11.5" text-anchor="middle">
|
||||
<rect x="822" y="174" width="236" height="32" rx="7" fill="#fff" stroke="#9cc0fb"/><text x="940" y="195" fill="#15181f">Anthropic</text>
|
||||
<rect x="822" y="214" width="236" height="32" rx="7" fill="#fff" stroke="#9cc0fb"/><text x="940" y="235" fill="#15181f">Google Gemini</text>
|
||||
<rect x="822" y="254" width="236" height="32" rx="7" fill="#fff" stroke="#9cc0fb"/><text x="940" y="275" fill="#15181f">OpenRouter</text>
|
||||
<rect x="822" y="294" width="236" height="32" rx="7" fill="#fff" stroke="#9cc0fb"/><text x="940" y="315" fill="#15181f">DeepSeek · Together · …</text>
|
||||
</g>
|
||||
<text x="940" y="356" font-size="10.5" fill="#3b6fd4" text-anchor="middle">any OpenAI-compatible gateway</text>
|
||||
<text x="940" y="378" font-size="10.5" fill="#7c8aa3" text-anchor="middle">via the shim's base_url</text>
|
||||
<path d="M720,172 L800,200" stroke="#64748b" stroke-width="1.4" fill="none" marker-end="url(#a)"/>
|
||||
<path d="M720,270 L800,250" stroke="#64748b" stroke-width="1.4" fill="none" marker-end="url(#a)"/>
|
||||
<path d="M720,368 L800,300" stroke="#64748b" stroke-width="1.4" fill="none" marker-end="url(#a)"/>
|
||||
|
||||
<!-- fail-loud -->
|
||||
<rect x="40" y="450" width="1040" height="60" rx="11" fill="#fef2f2" stroke="#ef4444" stroke-width="1.3"/>
|
||||
<text x="60" y="476" font-size="12.5" font-weight="700" fill="#b91c1c">Fail loud</text>
|
||||
<text x="60" y="496" font-size="11.5" fill="#7f1d1d">If the chosen path's SDK isn't installed, Hermes raises a <tspan font-family="monospace">RuntimeError</tspan> at startup — never a silent fallback to the wrong provider.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,62 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 520" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#9333ea"/></marker>
|
||||
<marker id="ai" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#4f46e5"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="520" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">MCP — one tool surface for every runtime</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">Tools reach agents over the Model Context Protocol. The platform exposes the same 80+ tools to any MCP client and to every workspace runtime alike.</text>
|
||||
|
||||
<!-- left: external MCP hosts -->
|
||||
<g filter="url(#sh)"><rect x="40" y="120" width="250" height="320" rx="13" fill="#faf5ff" stroke="#9333ea" stroke-width="1.5"/></g>
|
||||
<text x="165" y="148" font-size="13.5" font-weight="700" fill="#7c3aed" text-anchor="middle">Any MCP host</text>
|
||||
<g font-size="11.5" text-anchor="middle">
|
||||
<rect x="62" y="166" width="206" height="36" rx="8" fill="#fff" stroke="#e9d5ff"/><text x="165" y="189" fill="#15181f">Claude Desktop / Code</text>
|
||||
<rect x="62" y="210" width="206" height="36" rx="8" fill="#fff" stroke="#e9d5ff"/><text x="165" y="233" fill="#15181f">Cursor · IDEs</text>
|
||||
<rect x="62" y="254" width="206" height="36" rx="8" fill="#fff" stroke="#e9d5ff"/><text x="165" y="277" fill="#15181f">your own MCP client</text>
|
||||
</g>
|
||||
<text x="165" y="318" font-size="11" fill="#7c3aed" text-anchor="middle">@molecule-ai/mcp-server</text>
|
||||
<text x="165" y="336" font-size="10.5" fill="#6d28d9" text-anchor="middle">stdio · MOLECULE_URL</text>
|
||||
<text x="165" y="372" font-size="10.5" fill="#6d28d9" text-anchor="middle">drive the whole platform</text>
|
||||
<text x="165" y="388" font-size="10.5" fill="#6d28d9" text-anchor="middle">from outside</text>
|
||||
|
||||
<!-- center: platform MCP server -->
|
||||
<g filter="url(#sh)"><rect x="430" y="120" width="330" height="320" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="595" y="148" font-size="14" font-weight="700" fill="#3730a3" text-anchor="middle">Platform MCP surface</text>
|
||||
<text x="595" y="168" font-size="11" fill="#6366f1" text-anchor="middle">80+ tools, 1:1 with API routes</text>
|
||||
<g font-size="11" fill="#15181f" text-anchor="middle">
|
||||
<rect x="452" y="182" width="140" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="522" y="201">workspaces</text>
|
||||
<rect x="600" y="182" width="138" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="669" y="201">delegation</text>
|
||||
<rect x="452" y="218" width="140" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="522" y="237">memory</text>
|
||||
<rect x="600" y="218" width="138" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="669" y="237">secrets</text>
|
||||
<rect x="452" y="254" width="140" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="522" y="273">schedules</text>
|
||||
<rect x="600" y="254" width="138" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="669" y="273">approvals</text>
|
||||
<rect x="452" y="290" width="140" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="522" y="309">files</text>
|
||||
<rect x="600" y="290" width="138" height="30" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="669" y="309">channels · …</text>
|
||||
</g>
|
||||
<text x="595" y="350" font-size="11" fill="#4338ca" text-anchor="middle">a2a_mcp_server — auth + hierarchy ACL applied</text>
|
||||
<text x="595" y="368" font-size="10.5" fill="#6366f1" text-anchor="middle">same tools, whether called from outside or by an agent</text>
|
||||
<text x="595" y="392" font-size="10.5" fill="#6366f1" text-anchor="middle">tools self-authenticate from /configs/.auth_token</text>
|
||||
|
||||
<!-- right: in-workspace runtimes -->
|
||||
<g filter="url(#sh)"><rect x="900" y="120" width="260" height="320" rx="13" fill="#f8fafc" stroke="#0ea5e9" stroke-width="1.5"/></g>
|
||||
<text x="1030" y="148" font-size="13.5" font-weight="700" fill="#0369a1" text-anchor="middle">In-workspace runtimes</text>
|
||||
<text x="1030" y="168" font-size="10.5" fill="#5b6472" text-anchor="middle">MCP toolset, per framework</text>
|
||||
<g font-size="11.5" text-anchor="middle">
|
||||
<rect x="922" y="184" width="216" height="34" rx="8" fill="#fff" stroke="#bae6fd"/><text x="1030" y="206" fill="#15181f">claude-code (native MCP)</text>
|
||||
<rect x="922" y="226" width="216" height="34" rx="8" fill="#fff7ed" stroke="#f4b860"/><text x="1030" y="248" fill="#b45309">google-adk → McpToolset</text>
|
||||
<rect x="922" y="268" width="216" height="34" rx="8" fill="#fff" stroke="#bae6fd"/><text x="1030" y="290" fill="#15181f">langgraph · others</text>
|
||||
<rect x="922" y="310" width="216" height="34" rx="8" fill="#faf5ff" stroke="#d8b4fe"/><text x="1030" y="332" fill="#7c3aed">external / BYO agent</text>
|
||||
</g>
|
||||
<text x="1030" y="372" font-size="10.5" fill="#0369a1" text-anchor="middle">each adapter wraps the same</text>
|
||||
<text x="1030" y="388" font-size="10.5" fill="#0369a1" text-anchor="middle">tools natively (e.g. ADK FunctionTool)</text>
|
||||
|
||||
<!-- arrows -->
|
||||
<path d="M290,280 L430,280" stroke="#9333ea" stroke-width="2" fill="none" marker-end="url(#a)" marker-start="url(#a)"/>
|
||||
<text x="360" y="272" font-size="10.5" font-weight="700" fill="#7c3aed" text-anchor="middle">MCP</text>
|
||||
<path d="M760,280 L900,280" stroke="#0ea5e9" stroke-width="2" fill="none" marker-end="url(#a)" marker-start="url(#a)"/>
|
||||
<text x="830" y="272" font-size="10.5" font-weight="700" fill="#0369a1" text-anchor="middle">MCP</text>
|
||||
|
||||
<text x="40" y="478" font-size="11.5" fill="#5b6472">One protocol, two directions: drive Molecule from any MCP host, and give every workspace the same governed tools — no per-framework tool glue.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,71 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 640" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#f59e0b"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="640" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">org.yaml → a running org chart</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">One declarative template imports into a live tree of workspaces. Hierarchy comes from nesting — no edges to wire by hand.</text>
|
||||
|
||||
<!-- YAML panel -->
|
||||
<g filter="url(#sh)"><rect x="40" y="98" width="520" height="486" rx="13" fill="#1e242e"/></g>
|
||||
<text x="62" y="126" font-size="13" font-weight="700" fill="#e2e8f0" font-family="monospace">org.yaml</text>
|
||||
<g font-family="monospace" font-size="12.5">
|
||||
<text x="62" y="156" fill="#7dd3fc">org_name<tspan fill="#cbd5e1">: Acme Marketing</tspan></text>
|
||||
<text x="62" y="180" fill="#7dd3fc">defaults<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="86" y="200" fill="#a7f3d0">runtime<tspan fill="#cbd5e1">: claude-code</tspan></text>
|
||||
<text x="86" y="220" fill="#a7f3d0">tier<tspan fill="#cbd5e1">: 2</tspan></text>
|
||||
<text x="86" y="240" fill="#a7f3d0">plugins<tspan fill="#cbd5e1">: [molecule-audit]</tspan></text>
|
||||
<text x="62" y="264" fill="#7dd3fc">workspaces<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="86" y="284" fill="#fcd34d">lead<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="110" y="304" fill="#a7f3d0">role<tspan fill="#cbd5e1">: Marketing PM</tspan></text>
|
||||
<text x="110" y="324" fill="#a7f3d0">runtime<tspan fill="#cbd5e1">: google-adk</tspan></text>
|
||||
<text x="110" y="344" fill="#a7f3d0">children<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="134" y="364" fill="#fcd34d">research<tspan fill="#cbd5e1">: { role: Research }</tspan></text>
|
||||
<text x="134" y="384" fill="#fcd34d">writer<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="158" y="404" fill="#a7f3d0">role<tspan fill="#cbd5e1">: Content Writer</tspan></text>
|
||||
<text x="158" y="424" fill="#a7f3d0">plugins<tspan fill="#cbd5e1">: [!molecule-audit]</tspan></text>
|
||||
<text x="134" y="444" fill="#fcd34d">reviewer<tspan fill="#cbd5e1">: { role: Reviewer }</tspan></text>
|
||||
<text x="110" y="468" fill="#a7f3d0">schedules<tspan fill="#cbd5e1">: [daily-standup]</tspan></text>
|
||||
</g>
|
||||
<text x="62" y="506" font-size="11" fill="#94a3b8">defaults merge by UNION; <tspan fill="#fca5a5">!name</tspan> opts a workspace out.</text>
|
||||
<text x="62" y="528" font-size="11" fill="#94a3b8">per-workspace runtime/tier/plugins override defaults.</text>
|
||||
<text x="62" y="556" font-size="11.5" font-weight="700" fill="#fcd34d" font-family="monospace">POST /org/import (or Canvas template browser)</text>
|
||||
|
||||
<!-- import arrow -->
|
||||
<path d="M560,340 L636,340" stroke="#f59e0b" stroke-width="2.4" fill="none" marker-end="url(#a)"/>
|
||||
<text x="598" y="330" font-size="12" font-weight="700" fill="#b45309" text-anchor="middle">import</text>
|
||||
|
||||
<!-- rendered chart -->
|
||||
<g filter="url(#sh)"><rect x="648" y="98" width="512" height="486" rx="13" fill="#ffffff" stroke="#cdd3df" stroke-width="1.5"/></g>
|
||||
<text x="670" y="126" font-size="14" font-weight="700" fill="#0f172a">Rendered org (Canvas)</text>
|
||||
<g filter="url(#sh)"><rect x="820" y="150" width="168" height="52" rx="10" fill="#0f172a"/></g>
|
||||
<text x="904" y="172" font-size="13" font-weight="700" fill="#fff" text-anchor="middle">Marketing PM</text>
|
||||
<text x="904" y="190" font-size="10" fill="#cbd5e1" text-anchor="middle">google-adk · lead</text>
|
||||
<g filter="url(#sh)">
|
||||
<rect x="676" y="250" width="150" height="50" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.3"/>
|
||||
<rect x="838" y="250" width="150" height="50" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.3"/>
|
||||
<rect x="1000" y="250" width="148" height="50" rx="9" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.3"/>
|
||||
</g>
|
||||
<text x="751" y="272" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Research</text>
|
||||
<text x="751" y="289" font-size="9.5" fill="#5b6472" text-anchor="middle">claude-code · T2</text>
|
||||
<text x="913" y="272" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Content Writer</text>
|
||||
<text x="913" y="289" font-size="9.5" fill="#5b6472" text-anchor="middle">no audit plugin</text>
|
||||
<text x="1074" y="272" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Reviewer</text>
|
||||
<text x="1074" y="289" font-size="9.5" fill="#5b6472" text-anchor="middle">claude-code · T2</text>
|
||||
<g stroke="#94a3b8" stroke-width="1.4" fill="none">
|
||||
<path d="M904,202 L904,226 L751,226 L751,250"/>
|
||||
<path d="M904,226 L913,226 L913,250"/>
|
||||
<path d="M904,226 L1074,226 L1074,250"/>
|
||||
</g>
|
||||
<text x="670" y="360" font-size="12" fill="#334155">Each YAML key → a workspace node; <tspan font-family="monospace" fill="#4f46e5">children</tspan> → <tspan font-family="monospace" fill="#4f46e5">parent_id</tspan> nesting.</text>
|
||||
<text x="670" y="382" font-size="12" fill="#334155">Nesting sets the A2A comms rule + memory scope automatically.</text>
|
||||
<rect x="670" y="402" width="466" height="70" rx="10" fill="#fff7ed" stroke="#f4c98a"/>
|
||||
<text x="686" y="424" font-size="12" font-weight="700" fill="#b45309">Seeded on import</text>
|
||||
<text x="686" y="444" font-size="11" fill="#92560a">• schedules & plugins from the template (source=template)</text>
|
||||
<text x="686" y="460" font-size="11" fill="#92560a">• re-import refreshes template rows; runtime-added rows survive</text>
|
||||
<rect x="670" y="486" width="466" height="74" rx="10" fill="#ecfdf5" stroke="#10b981"/>
|
||||
<text x="686" y="508" font-size="12" font-weight="700" fill="#047857">Resolution rules</text>
|
||||
<text x="686" y="528" font-size="11" fill="#0f766e">plugins = defaults ∪ per-workspace (— or !name to remove)</text>
|
||||
<text x="686" y="544" font-size="11" fill="#0f766e">runtime / tier / model: per-workspace value wins over defaults</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,203 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1360 1240" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
<marker id="ai" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#4f46e5"/></marker>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
</defs>
|
||||
<rect width="1360" height="1240" fill="#fbfcfe"/>
|
||||
|
||||
<!-- ===== Title ===== -->
|
||||
<text x="44" y="48" font-size="26" font-weight="700" fill="#15181f">Molecule AI — the open-source OS for AI agent organizations</text>
|
||||
<text x="44" y="76" font-size="14" fill="#5b6472">Self-host the whole stack or use the hosted SaaS · provider-agnostic · plug in any runtime, model, or device · grow your ecosystem.</text>
|
||||
<g filter="url(#sh)"><rect x="44" y="92" width="470" height="30" rx="15" fill="#ecfdf5" stroke="#10b981" stroke-width="1.3"/></g>
|
||||
<text x="62" y="112" font-size="12.5" font-weight="700" fill="#047857">Open source · self-hostable · one binary · community ecosystem</text>
|
||||
|
||||
<!-- ===== SURFACES ===== -->
|
||||
<text x="44" y="156" font-size="12" font-weight="700" fill="#64748b" letter-spacing="0.4">SURFACES — how you drive & reach the org</text>
|
||||
<g filter="url(#sh)">
|
||||
<rect x="44" y="166" width="232" height="60" rx="11" fill="#f6f4ff" stroke="#7c6df2" stroke-width="1.4"/>
|
||||
<rect x="290" y="166" width="232" height="60" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
<rect x="536" y="166" width="232" height="60" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
<rect x="782" y="166" width="248" height="60" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
<rect x="1044" y="166" width="272" height="60" rx="11" fill="#ffffff" stroke="#cdd3df" stroke-width="1.4"/>
|
||||
</g>
|
||||
<text x="160" y="192" font-size="13" font-weight="700" fill="#3b2fae" text-anchor="middle">Canvas</text>
|
||||
<text x="160" y="211" font-size="10.5" fill="#5b6472" text-anchor="middle">React-Flow org-chart UI</text>
|
||||
<text x="406" y="192" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">molecli (CLI)</text>
|
||||
<text x="406" y="211" font-size="10.5" fill="#5b6472" text-anchor="middle">scriptable control</text>
|
||||
<text x="652" y="192" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">MCP server</text>
|
||||
<text x="652" y="211" font-size="10.5" fill="#5b6472" text-anchor="middle">tools for any MCP host</text>
|
||||
<text x="906" y="192" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Channels</text>
|
||||
<text x="906" y="211" font-size="10.5" fill="#5b6472" text-anchor="middle">telegram · slack · discord · lark</text>
|
||||
<text x="1180" y="192" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">REST API / SDK</text>
|
||||
<text x="1180" y="211" font-size="10.5" fill="#5b6472" text-anchor="middle">automate everything</text>
|
||||
|
||||
<g stroke="#64748b" stroke-width="1.3" fill="none">
|
||||
<path d="M160,226 L160,250" marker-end="url(#a)"/>
|
||||
<path d="M406,226 L406,250" marker-end="url(#a)"/>
|
||||
<path d="M652,226 L652,250" marker-end="url(#a)"/>
|
||||
<path d="M906,226 L906,250" marker-end="url(#a)"/>
|
||||
<path d="M1180,226 L1180,250" marker-end="url(#a)"/>
|
||||
</g>
|
||||
|
||||
<!-- ===== CONTROL PLANE ===== -->
|
||||
<g filter="url(#sh)"><rect x="44" y="252" width="1272" height="196" rx="16" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.7"/></g>
|
||||
<text x="66" y="282" font-size="17" font-weight="700" fill="#3730a3">Control Plane · Platform</text>
|
||||
<text x="300" y="282" font-size="12" fill="#6366f1">Go / Gin — the orchestration core (open source)</text>
|
||||
<g font-size="11.5" fill="#15181f" text-anchor="middle">
|
||||
<rect x="66" y="298" width="232" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="182" y="320" font-weight="600">Provisioner</text><text x="182" y="334" font-size="10" fill="#5b6472">spawns workspace machines</text>
|
||||
<rect x="312" y="298" width="248" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="436" y="320" font-weight="600">Registry + Discovery</text><text x="436" y="334" font-size="10" fill="#5b6472">CanCommunicate (hierarchy ACL)</text>
|
||||
<rect x="574" y="298" width="186" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="667" y="320" font-weight="600">A2A Proxy</text><text x="667" y="334" font-size="10" fill="#5b6472">canvas → agent</text>
|
||||
<rect x="774" y="298" width="200" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="874" y="320" font-weight="600">WebSocket Hub</text><text x="874" y="334" font-size="10" fill="#5b6472">live event fan-out</text>
|
||||
<rect x="988" y="298" width="150" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="1063" y="320" font-weight="600">Scheduler</text><text x="1063" y="334" font-size="10" fill="#5b6472">cron → A2A</text>
|
||||
<rect x="1152" y="298" width="142" height="42" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="1223" y="320" font-weight="600">Secrets</text><text x="1223" y="334" font-size="10" fill="#5b6472">per-workspace</text>
|
||||
<rect x="66" y="350" width="180" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="156" y="373" font-weight="600">Budget & metrics</text>
|
||||
<rect x="260" y="350" width="160" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="340" y="373" font-weight="600">Audit ledger</text>
|
||||
<rect x="434" y="350" width="190" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="529" y="373" font-weight="600">Event store (sourced)</text>
|
||||
<rect x="638" y="350" width="150" height="38" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="713" y="373" font-weight="600">Channels</text>
|
||||
</g>
|
||||
<g filter="url(#sh)">
|
||||
<rect x="1004" y="350" width="140" height="42" rx="9" fill="#ffffff" stroke="#94a3b8"/>
|
||||
<rect x="1156" y="350" width="138" height="42" rx="9" fill="#ffffff" stroke="#94a3b8"/>
|
||||
</g>
|
||||
<text x="1074" y="368" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Postgres</text>
|
||||
<text x="1074" y="383" font-size="9.5" fill="#5b6472" text-anchor="middle">event-sourced SoT</text>
|
||||
<text x="1225" y="368" font-size="12" font-weight="700" fill="#15181f" text-anchor="middle">Redis</text>
|
||||
<text x="1225" y="383" font-size="9.5" fill="#5b6472" text-anchor="middle">liveness · pub/sub</text>
|
||||
<text x="66" y="418" font-size="11.5" fill="#4338ca">In the <tspan font-weight="700">discovery / provisioning / governance</tspan> path — never in the agent↔agent data path.</text>
|
||||
<text x="66" y="436" font-size="11.5" fill="#6366f1">SaaS: one isolated tenant per org. Self-host: same binary, your infrastructure.</text>
|
||||
|
||||
<g stroke="#4f46e5" stroke-width="1.6" fill="none">
|
||||
<path d="M300,448 L300,486" marker-end="url(#ai)"/><text x="308" y="472" font-size="11" font-weight="700" fill="#4338ca">provision</text>
|
||||
<path d="M620,486 L620,448" marker-end="url(#ai)" stroke-dasharray="5 4"/><text x="628" y="472" font-size="10.5" fill="#6366f1">register · heartbeat</text>
|
||||
<path d="M900,448 L900,486" marker-end="url(#ai)" stroke-dasharray="5 4"/><text x="908" y="472" font-size="10.5" fill="#6366f1">events</text>
|
||||
</g>
|
||||
|
||||
<!-- ===== ORG TENANT — physical-machine isolation ===== -->
|
||||
<g filter="url(#sh)"><rect x="44" y="488" width="1272" height="276" rx="16" fill="#ffffff" stroke="#cdd3df" stroke-width="1.7"/></g>
|
||||
<text x="66" y="516" font-size="16" font-weight="700" fill="#0f172a">Org Tenant — a hierarchy of Workspaces</text>
|
||||
<text x="430" y="516" font-size="12" fill="#64748b">each Workspace = one agent on its OWN dedicated machine · pluggable runtime · per-workspace token</text>
|
||||
|
||||
<!-- root machine -->
|
||||
<g filter="url(#sh)"><rect x="585" y="536" width="190" height="58" rx="10" fill="#0f172a"/></g>
|
||||
<text x="680" y="560" font-size="13" font-weight="700" fill="#fff" text-anchor="middle">Org Lead</text>
|
||||
<text x="680" y="578" font-size="9.5" fill="#cbd5e1" text-anchor="middle">root · own machine</text>
|
||||
|
||||
<!-- three child machines, each in its own hard-gated box -->
|
||||
<g filter="url(#sh)">
|
||||
<rect x="300" y="636" width="220" height="84" rx="11" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="570" y="636" width="220" height="84" rx="11" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
<rect x="840" y="636" width="220" height="84" rx="11" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/>
|
||||
</g>
|
||||
<!-- machine chrome line per box -->
|
||||
<g font-size="9" fill="#94a3b8" text-anchor="middle">
|
||||
<text x="410" y="654">▢ dedicated EC2 · own OS · own filesystem</text>
|
||||
<text x="680" y="654">▢ dedicated EC2 · own OS · own filesystem</text>
|
||||
<text x="950" y="654">▢ dedicated EC2 · own OS · own filesystem</text>
|
||||
</g>
|
||||
<text x="410" y="682" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Agent</text>
|
||||
<text x="410" y="700" font-size="10" fill="#5b6472" text-anchor="middle">runtime · tier · skills · secrets</text>
|
||||
<text x="680" y="682" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Team Lead</text>
|
||||
<text x="680" y="700" font-size="10" fill="#5b6472" text-anchor="middle">coordinator</text>
|
||||
<text x="950" y="682" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Agent</text>
|
||||
<text x="950" y="700" font-size="10" fill="#5b6472" text-anchor="middle">specialist</text>
|
||||
|
||||
<!-- structure connectors -->
|
||||
<g stroke="#94a3b8" stroke-width="1.4" fill="none">
|
||||
<path d="M680,594 L680,614 L410,614 L410,636"/>
|
||||
<path d="M680,614 L680,636"/>
|
||||
<path d="M680,614 L950,614 L950,636"/>
|
||||
</g>
|
||||
|
||||
<!-- hard gates between machines -->
|
||||
<g>
|
||||
<line x1="545" y1="632" x2="545" y2="724" stroke="#ef4444" stroke-width="2" stroke-dasharray="3 4"/>
|
||||
<line x1="815" y1="632" x2="815" y2="724" stroke="#ef4444" stroke-width="2" stroke-dasharray="3 4"/>
|
||||
</g>
|
||||
<text x="545" y="740" font-size="10" fill="#dc2626" text-anchor="middle">hard gate</text>
|
||||
<text x="815" y="740" font-size="10" fill="#dc2626" text-anchor="middle">hard gate</text>
|
||||
|
||||
<!-- A2A only-channel arcs (siblings allowed) -->
|
||||
<path d="M520,648 C545,624 570,624 570,648" stroke="#10b981" stroke-width="2.2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<path d="M790,648 C815,624 840,624 840,648" stroke="#10b981" stroke-width="2.2" fill="none" marker-end="url(#ag)" marker-start="url(#ag)"/>
|
||||
<text x="1086" y="650" font-size="12" font-weight="700" fill="#047857">A2A — the ONLY channel</text>
|
||||
<text x="1086" y="668" font-size="10.5" fill="#0f766e">network-only · hierarchy-gated.</text>
|
||||
<text x="1086" y="684" font-size="10.5" fill="#dc2626">No shared FS / env / secrets —</text>
|
||||
<text x="1086" y="699" font-size="10.5" fill="#dc2626">a workspace cannot touch another's.</text>
|
||||
|
||||
<!-- governance chip -->
|
||||
<rect x="66" y="636" width="200" height="84" rx="10" fill="#ecfdf5" stroke="#10b981" stroke-width="1.2"/>
|
||||
<text x="82" y="660" font-size="12" font-weight="700" fill="#047857">Governance layer</text>
|
||||
<text x="82" y="680" font-size="10" fill="#0f766e">discovery · access-control</text>
|
||||
<text x="82" y="696" font-size="10" fill="#0f766e">memory scope · approvals</text>
|
||||
<text x="82" y="712" font-size="10" fill="#0f766e">the org chart IS the ACL</text>
|
||||
|
||||
<!-- ===== DEEP MEMORY ===== -->
|
||||
<g filter="url(#sh)"><rect x="44" y="784" width="1272" height="150" rx="16" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.6"/></g>
|
||||
<text x="66" y="811" font-size="16" font-weight="700" fill="#b45309">Deep memory — hierarchical & namespaced (HMA)</text>
|
||||
<text x="610" y="811" font-size="11.5" fill="#92560a">durable per-workspace namespace · scoped reach follows the org tree</text>
|
||||
<!-- nested scopes -->
|
||||
<rect x="66" y="826" width="700" height="92" rx="10" fill="#fffdf7" stroke="#f4b860"/>
|
||||
<text x="84" y="848" font-size="12.5" font-weight="700" fill="#b45309">GLOBAL</text>
|
||||
<text x="150" y="848" font-size="10.5" fill="#92560a">read-all · write from root — org-wide knowledge</text>
|
||||
<rect x="84" y="856" width="540" height="54" rx="9" fill="#fff8ee" stroke="#f4c98a"/>
|
||||
<text x="100" y="876" font-size="12.5" font-weight="700" fill="#b45309">TEAM</text>
|
||||
<text x="152" y="876" font-size="10.5" fill="#92560a">parent + siblings — shared team context</text>
|
||||
<rect x="100" y="884" width="320" height="20" rx="6" fill="#fff" stroke="#f4d3a4"/>
|
||||
<text x="116" y="899" font-size="11.5" font-weight="700" fill="#b45309">LOCAL</text>
|
||||
<text x="166" y="899" font-size="10" fill="#92560a">self only — private working memory</text>
|
||||
<!-- surfaces + promotion -->
|
||||
<text x="800" y="850" font-size="11.5" font-weight="700" fill="#92560a">Surfaces</text>
|
||||
<text x="800" y="868" font-size="10.5" fill="#92560a">• agent_memories (scoped) • KV / canvas memory</text>
|
||||
<text x="800" y="884" font-size="10.5" fill="#92560a">• session recall (search) • awareness namespace</text>
|
||||
<text x="800" y="906" font-size="10.5" font-weight="600" fill="#b45309">promotion: memory → repeated success → skill (hot-reload)</text>
|
||||
|
||||
<!-- arrow tenant -> runtimes -->
|
||||
<path d="M410,720 L410,756 L300,756 L300,968" stroke="#64748b" stroke-width="1.4" fill="none" marker-end="url(#a)"/>
|
||||
<text x="312" y="958" font-size="10.5" fill="#475569">each workspace selects a runtime ▸</text>
|
||||
|
||||
<!-- ===== PLUGGABLE RUNTIMES + DEVICES ===== -->
|
||||
<text x="44" y="970" font-size="12" font-weight="700" fill="#64748b" letter-spacing="0.4">PLUGGABLE RUNTIMES — any agent, any device (one BaseAdapter contract)</text>
|
||||
<g filter="url(#sh)"><rect x="44" y="980" width="860" height="222" rx="14" fill="#f8fafc" stroke="#0ea5e9" stroke-width="1.5"/></g>
|
||||
|
||||
<text x="66" y="1006" font-size="13" font-weight="700" fill="#0369a1">Software agent frameworks</text>
|
||||
<g font-size="11.5" font-weight="600" text-anchor="middle">
|
||||
<rect x="66" y="1016" width="148" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="140" y="1037" fill="#15181f">claude-code</text>
|
||||
<rect x="224" y="1016" width="148" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="298" y="1037" fill="#15181f">langgraph</text>
|
||||
<rect x="382" y="1016" width="130" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="447" y="1037" fill="#15181f">crewai</text>
|
||||
<rect x="522" y="1016" width="130" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="587" y="1037" fill="#15181f">autogen</text>
|
||||
<rect x="662" y="1016" width="150" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="737" y="1037" fill="#15181f">deepagents</text>
|
||||
<rect x="66" y="1056" width="130" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="131" y="1077" fill="#15181f">openclaw</text>
|
||||
<rect x="206" y="1056" width="120" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="266" y="1077" fill="#15181f">hermes</text>
|
||||
<rect x="336" y="1056" width="130" height="32" rx="8" fill="#fff" stroke="#bae6fd"/><text x="401" y="1077" fill="#15181f">gemini-cli</text>
|
||||
<rect x="476" y="1056" width="146" height="32" rx="8" fill="#fff7ed" stroke="#f4b860"/><text x="549" y="1077" fill="#b45309">google-adk</text>
|
||||
<rect x="632" y="1056" width="180" height="32" rx="8" fill="#faf5ff" stroke="#d8b4fe"/><text x="722" y="1077" fill="#7c3aed">external / BYO agent</text>
|
||||
</g>
|
||||
|
||||
<line x1="66" y1="1104" x2="884" y2="1104" stroke="#e2e8f0" stroke-width="1"/>
|
||||
<text x="66" y="1126" font-size="13" font-weight="700" fill="#0369a1">Embodied & edge devices <tspan font-size="10.5" font-weight="500" fill="#94a3b8">— roadmap</tspan></text>
|
||||
<g font-size="11.5" font-weight="600" text-anchor="middle" fill="#0f172a">
|
||||
<rect x="66" y="1136" width="150" height="34" rx="8" fill="#f0f9ff" stroke="#7dd3fc"/><text x="141" y="1158">smart glasses</text>
|
||||
<rect x="226" y="1136" width="120" height="34" rx="8" fill="#f0f9ff" stroke="#7dd3fc"/><text x="286" y="1158">watches</text>
|
||||
<rect x="356" y="1136" width="120" height="34" rx="8" fill="#f0f9ff" stroke="#7dd3fc"/><text x="416" y="1158">robots</text>
|
||||
<rect x="486" y="1136" width="170" height="34" rx="8" fill="#f0f9ff" stroke="#7dd3fc"/><text x="571" y="1158">home / building systems</text>
|
||||
<rect x="666" y="1136" width="150" height="34" rx="8" fill="#f0f9ff" stroke="#7dd3fc"/><text x="741" y="1158">vehicles · IoT · …</text>
|
||||
</g>
|
||||
<text x="66" y="1192" font-size="10.5" fill="#5b6472">Any A2A/MCP-speaking endpoint — a software agent OR an intelligent device — registers as a governed workspace in the org.</text>
|
||||
|
||||
<!-- providers -->
|
||||
<g filter="url(#sh)"><rect x="920" y="980" width="396" height="222" rx="14" fill="#e8f0fe" stroke="#4285f4" stroke-width="1.5"/></g>
|
||||
<text x="942" y="1006" font-size="13" font-weight="700" fill="#1a56c4">Model providers</text>
|
||||
<text x="942" y="1024" font-size="10.5" fill="#3b6fd4">runtimes call whichever the model id names</text>
|
||||
<g font-size="11.5" font-weight="600" text-anchor="middle">
|
||||
<rect x="942" y="1036" width="354" height="32" rx="8" fill="#fff" stroke="#9cc0fb"/><text x="1119" y="1057" fill="#15181f">Anthropic (Claude)</text>
|
||||
<rect x="942" y="1076" width="354" height="32" rx="8" fill="#fff" stroke="#9cc0fb"/><text x="1119" y="1097" fill="#15181f">OpenAI & OpenAI-compatible</text>
|
||||
<rect x="942" y="1116" width="354" height="32" rx="8" fill="#fff" stroke="#4285f4" stroke-width="1.5"/><text x="1119" y="1137" fill="#1a56c4">Google Vertex AI · Gemini</text>
|
||||
</g>
|
||||
<text x="942" y="1172" font-size="10" fill="#3b6fd4">+ OpenRouter and any OpenAI-compatible gateway.</text>
|
||||
<text x="942" y="1190" font-size="10" fill="#7c8aa3">Orchestration core is provider-agnostic — all swappable.</text>
|
||||
|
||||
<!-- runtime -> provider -->
|
||||
<path d="M904,1090 L920,1090" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,64 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 560" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
|
||||
<marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#f59e0b"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="560" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Schedules — cron that wakes an agent</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">A 30s scheduler loop fires due schedules as A2A messages (caller <tspan font-family="monospace" fill="#4f46e5">system:scheduler</tspan>), bounded by a concurrency semaphore.</text>
|
||||
|
||||
<!-- scheduler loop -->
|
||||
<g filter="url(#sh)"><rect x="40" y="120" width="250" height="150" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="165" y="150" font-size="14" font-weight="700" fill="#3730a3" text-anchor="middle">Scheduler</text>
|
||||
<text x="165" y="172" font-size="11.5" fill="#6366f1" text-anchor="middle">polls every 30s</text>
|
||||
<text x="165" y="198" font-size="11.5" fill="#15181f" text-anchor="middle">SELECT due rows</text>
|
||||
<text x="165" y="216" font-size="11" fill="#5b6472" text-anchor="middle">next_run_at <= now (≤ 50)</text>
|
||||
<text x="165" y="244" font-size="10.5" fill="#6366f1" text-anchor="middle">liveness watchdog · panic-recover</text>
|
||||
|
||||
<!-- table -->
|
||||
<g filter="url(#sh)"><rect x="40" y="300" width="250" height="100" rx="11" fill="#ffffff" stroke="#94a3b8"/></g>
|
||||
<text x="165" y="328" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">workspace_schedules</text>
|
||||
<text x="165" y="350" font-size="10.5" fill="#5b6472" text-anchor="middle">cron_expr · timezone · prompt</text>
|
||||
<text x="165" y="368" font-size="10.5" fill="#5b6472" text-anchor="middle">last_run · run_count · next_run</text>
|
||||
<text x="165" y="386" font-size="10.5" fill="#5b6472" text-anchor="middle">last_status</text>
|
||||
<path d="M165,300 L165,270" stroke="#64748b" stroke-width="1.3" fill="none" marker-end="url(#a)" marker-start="url(#a)"/>
|
||||
|
||||
<!-- semaphore -->
|
||||
<g filter="url(#sh)"><rect x="360" y="160" width="220" height="80" rx="12" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.5"/></g>
|
||||
<text x="470" y="190" font-size="13" font-weight="700" fill="#b45309" text-anchor="middle">Concurrency gate</text>
|
||||
<text x="470" y="212" font-size="11" fill="#92560a" text-anchor="middle">semaphore — ≤ 10 in-flight</text>
|
||||
<text x="470" y="228" font-size="10.5" fill="#92560a" text-anchor="middle">5-min per-run timeout</text>
|
||||
<path d="M290,195 L360,197" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
<text x="300" y="186" font-size="10.5" fill="#475569">fire due</text>
|
||||
|
||||
<!-- workspace -->
|
||||
<g filter="url(#sh)"><rect x="660" y="150" width="230" height="100" rx="13" fill="#ffffff" stroke="#5b5bd6" stroke-width="1.5"/></g>
|
||||
<text x="775" y="186" font-size="14" font-weight="700" fill="#15181f" text-anchor="middle">Workspace agent</text>
|
||||
<text x="775" y="210" font-size="11" fill="#5b6472" text-anchor="middle">runs the scheduled prompt</text>
|
||||
<text x="775" y="232" font-size="10.5" fill="#7c6df2" text-anchor="middle">A2A message/send</text>
|
||||
<path d="M580,200 L660,200" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#ag)"/>
|
||||
<text x="600" y="190" font-size="10.5" font-weight="700" fill="#047857">A2A</text>
|
||||
|
||||
<!-- outcome -->
|
||||
<g filter="url(#sh)"><rect x="960" y="150" width="200" height="100" rx="12" fill="#ffffff" stroke="#cdd3df"/></g>
|
||||
<text x="1060" y="178" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Record outcome</text>
|
||||
<text x="1060" y="200" font-size="11" fill="#5b6472" text-anchor="middle">update last_run / next_run</text>
|
||||
<text x="1060" y="218" font-size="11" fill="#5b6472" text-anchor="middle">log activity (cron_run)</text>
|
||||
<text x="1060" y="238" font-size="10.5" fill="#5b6472" text-anchor="middle">success / error / skipped</text>
|
||||
<path d="M890,200 L960,200" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
<!-- recompute loop back -->
|
||||
<path d="M1060,250 C1060,300 165,300 165,280" stroke="#f59e0b" stroke-width="1.6" fill="none" stroke-dasharray="5 4" marker-end="url(#ar)"/>
|
||||
<text x="600" y="296" font-size="10.5" fill="#b45309">recompute next_run → back into the table</text>
|
||||
|
||||
<!-- statuses -->
|
||||
<rect x="40" y="430" width="1120" height="100" rx="11" fill="#f8fafc" stroke="#cdd3df"/>
|
||||
<text x="60" y="456" font-size="12.5" font-weight="700" fill="#15181f">Outcomes & resilience</text>
|
||||
<g font-size="11.5">
|
||||
<rect x="60" y="470" width="16" height="16" rx="4" fill="#ecfdf5" stroke="#10b981"/><text x="84" y="483" fill="#475569"><tspan font-weight="700" fill="#047857">success</tspan> — agent ran & replied</text>
|
||||
<rect x="320" y="470" width="16" height="16" rx="4" fill="#fef2f2" stroke="#ef4444"/><text x="344" y="483" fill="#475569"><tspan font-weight="700" fill="#dc2626">error</tspan> — run failed (logged)</text>
|
||||
<rect x="560" y="470" width="16" height="16" rx="4" fill="#fff7ed" stroke="#f59e0b"/><text x="584" y="483" fill="#475569"><tspan font-weight="700" fill="#b45309">skipped</tspan> — workspace busy</text>
|
||||
</g>
|
||||
<text x="60" y="512" font-size="11.5" fill="#475569">Seeded from <tspan font-family="monospace" fill="#4f46e5">org.yaml</tspan> on import (idempotent) · panic-recovery per tick · cross-org admin health flags phantom / consecutive-empty schedulers.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,74 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 560" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
</defs>
|
||||
<rect width="1100" height="560" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Self-hosting topology</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">The whole open-source stack runs on one Docker network. Same binary as SaaS — single-org, your infrastructure, your keys.</text>
|
||||
|
||||
<!-- docker network frame -->
|
||||
<g filter="url(#sh)"><rect x="40" y="100" width="1020" height="350" rx="16" fill="#ffffff" stroke="#4f46e5" stroke-width="1.6" stroke-dasharray="6 4"/></g>
|
||||
<text x="60" y="128" font-size="13" font-weight="700" fill="#3730a3">molecule-monorepo-net (Docker network)</text>
|
||||
|
||||
<!-- canvas + platform -->
|
||||
<g filter="url(#sh)"><rect x="70" y="150" width="220" height="80" rx="11" fill="#f6f4ff" stroke="#7c6df2" stroke-width="1.4"/></g>
|
||||
<text x="180" y="180" font-size="13.5" font-weight="700" fill="#3b2fae" text-anchor="middle">Canvas</text>
|
||||
<text x="180" y="200" font-size="11" fill="#5b6472" text-anchor="middle">Next.js · :3000</text>
|
||||
<text x="180" y="218" font-size="10.5" fill="#7c6df2" text-anchor="middle">operator UI</text>
|
||||
|
||||
<g filter="url(#sh)"><rect x="330" y="150" width="240" height="80" rx="11" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/></g>
|
||||
<text x="450" y="180" font-size="13.5" font-weight="700" fill="#3730a3" text-anchor="middle">Platform (Go)</text>
|
||||
<text x="450" y="200" font-size="11" fill="#6366f1" text-anchor="middle">control plane · :8080</text>
|
||||
<text x="450" y="218" font-size="10.5" fill="#6366f1" text-anchor="middle">prod: one image w/ Canvas (Dockerfile.tenant)</text>
|
||||
|
||||
<path d="M290,190 L330,190" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)" marker-start="url(#a)"/>
|
||||
<text x="310" y="182" font-size="9.5" fill="#475569" text-anchor="middle">REST · /ws</text>
|
||||
|
||||
<!-- infra services row -->
|
||||
<g filter="url(#sh)">
|
||||
<rect x="70" y="270" width="150" height="76" rx="10" fill="#fff" stroke="#94a3b8"/>
|
||||
<rect x="240" y="270" width="150" height="76" rx="10" fill="#fff" stroke="#94a3b8"/>
|
||||
<rect x="410" y="270" width="170" height="76" rx="10" fill="#fff" stroke="#94a3b8"/>
|
||||
<rect x="600" y="270" width="160" height="76" rx="10" fill="#fff" stroke="#94a3b8"/>
|
||||
</g>
|
||||
<text x="145" y="296" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Postgres</text>
|
||||
<text x="145" y="316" font-size="10.5" fill="#5b6472" text-anchor="middle">:5432 · source of truth</text>
|
||||
<text x="145" y="333" font-size="10" fill="#94a3b8" text-anchor="middle">event-sourced</text>
|
||||
<text x="315" y="296" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Redis</text>
|
||||
<text x="315" y="316" font-size="10.5" fill="#5b6472" text-anchor="middle">:6379 · liveness</text>
|
||||
<text x="315" y="333" font-size="10" fill="#94a3b8" text-anchor="middle">pub/sub · TTL</text>
|
||||
<text x="495" y="296" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Langfuse</text>
|
||||
<text x="495" y="316" font-size="10.5" fill="#5b6472" text-anchor="middle">:3001 · traces/cost</text>
|
||||
<text x="495" y="333" font-size="10" fill="#94a3b8" text-anchor="middle">(+ ClickHouse)</text>
|
||||
<text x="680" y="296" font-size="12.5" font-weight="700" fill="#15181f" text-anchor="middle">Temporal</text>
|
||||
<text x="680" y="316" font-size="10.5" fill="#5b6472" text-anchor="middle">:7233 / :8233</text>
|
||||
<text x="680" y="333" font-size="10" fill="#94a3b8" text-anchor="middle">durable workflows</text>
|
||||
|
||||
<!-- workspaces -->
|
||||
<g filter="url(#sh)"><rect x="800" y="150" width="230" height="196" rx="11" fill="#f8fafc" stroke="#5b5bd6" stroke-width="1.4"/></g>
|
||||
<text x="915" y="176" font-size="13" font-weight="700" fill="#15181f" text-anchor="middle">Workspace containers</text>
|
||||
<g font-size="11" text-anchor="middle">
|
||||
<rect x="820" y="190" width="190" height="32" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="915" y="211" fill="#15181f">agent · tier T1–T4</text>
|
||||
<rect x="820" y="228" width="190" height="32" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="915" y="249" fill="#15181f">agent · pluggable runtime</text>
|
||||
<rect x="820" y="266" width="190" height="32" rx="7" fill="#fff" stroke="#c7cdf5"/><text x="915" y="287" fill="#15181f">agent · A2A server</text>
|
||||
</g>
|
||||
<text x="915" y="320" font-size="10.5" fill="#6366f1" text-anchor="middle">provisioned by the platform;</text>
|
||||
<text x="915" y="336" font-size="10.5" fill="#6366f1" text-anchor="middle">register + heartbeat back</text>
|
||||
|
||||
<!-- platform -> infra + workspaces arrows -->
|
||||
<g stroke="#64748b" stroke-width="1.4" fill="none">
|
||||
<path d="M450,230 L145,270" marker-end="url(#a)"/>
|
||||
<path d="M450,230 L315,270" marker-end="url(#a)"/>
|
||||
<path d="M470,230 L495,270" marker-end="url(#a)"/>
|
||||
<path d="M500,230 L680,270" marker-end="url(#a)"/>
|
||||
<path d="M570,188 L800,200" marker-end="url(#a)"/>
|
||||
</g>
|
||||
<text x="690" y="186" font-size="9.5" fill="#475569">provision · A2A proxy</text>
|
||||
|
||||
<!-- secrets note -->
|
||||
<rect x="40" y="468" width="1020" height="76" rx="11" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.3"/>
|
||||
<text x="60" y="494" font-size="12.5" font-weight="700" fill="#b45309">Secrets at rest</text>
|
||||
<text x="60" y="516" font-size="11.5" fill="#92560a">Static AES-256-GCM (<tspan font-family="monospace">SECRETS_ENCRYPTION_KEY</tspan>) or KMS envelope (<tspan font-family="monospace">KMS_KEY_ARN</tspan>, per-secret DEK). The platform refuses to boot with neither.</text>
|
||||
<text x="60" y="534" font-size="11" fill="#b45309">SaaS adds a Cloudflare wildcard-DNS edge in front of per-tenant instances; self-host skips that — everything inside the box is identical.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 600" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="600" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">Credential model — three scoped tiers</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">Each credential authorizes a different blast radius. Authority narrows top → bottom; nothing crosses an org boundary.</text>
|
||||
|
||||
<!-- Tier 1: admin -->
|
||||
<g filter="url(#sh)"><rect x="40" y="104" width="1120" height="120" rx="13" fill="#fef2f2" stroke="#ef4444" stroke-width="1.6"/></g>
|
||||
<text x="64" y="134" font-size="15" font-weight="700" fill="#b91c1c">ADMIN_TOKEN — control-plane / break-glass</text>
|
||||
<text x="64" y="160" font-size="12" fill="#7f1d1d">Scope: <tspan font-family="monospace">/admin/*</tspan> across the deployment (AdminAuth). Self-host / operator only.</text>
|
||||
<text x="64" y="180" font-size="12" fill="#7f1d1d">Mints org API keys. Highest authority — keep out of agents & CI.</text>
|
||||
<text x="64" y="202" font-size="11" fill="#b91c1c" font-family="monospace">middleware: AdminAuth · routes: /admin/*</text>
|
||||
<rect x="900" y="128" width="236" height="72" rx="10" fill="#fff" stroke="#fca5a5"/>
|
||||
<text x="1018" y="152" font-size="11.5" font-weight="700" fill="#b91c1c" text-anchor="middle">authorizes</text>
|
||||
<text x="1018" y="172" font-size="11" fill="#7f1d1d" text-anchor="middle">entire control plane</text>
|
||||
<text x="1018" y="190" font-size="11" fill="#7f1d1d" text-anchor="middle">+ all orgs on it</text>
|
||||
|
||||
<path d="M120,224 L120,254" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
<text x="132" y="245" font-size="11" fill="#475569">mints ↓</text>
|
||||
|
||||
<!-- Tier 2: org key -->
|
||||
<g filter="url(#sh)"><rect x="40" y="256" width="1120" height="120" rx="13" fill="#fff7ed" stroke="#f59e0b" stroke-width="1.6"/></g>
|
||||
<text x="64" y="286" font-size="15" font-weight="700" fill="#b45309">Org API key — full org admin</text>
|
||||
<text x="64" y="312" font-size="12" fill="#92560a">Scope: everything inside ONE org (<tspan font-family="monospace">/org/*</tspan>). Named, creation-attributed, audited, revocable.</text>
|
||||
<text x="64" y="332" font-size="12" fill="#92560a">Cannot touch the control plane or other orgs. Use for org-level automation / integrations.</text>
|
||||
<text x="64" y="354" font-size="11" fill="#b45309" font-family="monospace">issue: /org/tokens · attribution: org-token:<name></text>
|
||||
<rect x="900" y="280" width="236" height="72" rx="10" fill="#fff" stroke="#f4c98a"/>
|
||||
<text x="1018" y="304" font-size="11.5" font-weight="700" fill="#b45309" text-anchor="middle">authorizes</text>
|
||||
<text x="1018" y="324" font-size="11" fill="#92560a" text-anchor="middle">one org (all its</text>
|
||||
<text x="1018" y="342" font-size="11" fill="#92560a" text-anchor="middle">workspaces & settings)</text>
|
||||
|
||||
<path d="M120,376 L120,406" stroke="#64748b" stroke-width="1.6" fill="none" marker-end="url(#a)"/>
|
||||
<text x="132" y="397" font-size="11" fill="#475569">scopes ↓</text>
|
||||
|
||||
<!-- Tier 3: workspace bearer -->
|
||||
<g filter="url(#sh)"><rect x="40" y="408" width="1120" height="128" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="64" y="438" font-size="15" font-weight="700" fill="#3730a3">Workspace bearer token — one workspace</text>
|
||||
<text x="64" y="464" font-size="12" fill="#4338ca">Scope: a single workspace (<tspan font-family="monospace">/workspaces/:id/*</tspan>). 256-bit, sha256-stored, shown once, no expiry.</text>
|
||||
<text x="64" y="484" font-size="12" fill="#4338ca">Issued at first <tspan font-family="monospace">/registry/register</tspan>; auto-revoked on delete. Rotate = create → verify → revoke.</text>
|
||||
<text x="64" y="506" font-size="12" fill="#4338ca">This is the only credential an agent (or external/remote agent) holds.</text>
|
||||
<text x="64" y="526" font-size="11" fill="#3730a3" font-family="monospace">middleware: WorkspaceAuth · header: Authorization: Bearer …</text>
|
||||
<rect x="900" y="432" width="236" height="80" rx="10" fill="#fff" stroke="#c7cdf5"/>
|
||||
<text x="1018" y="456" font-size="11.5" font-weight="700" fill="#3730a3" text-anchor="middle">authorizes</text>
|
||||
<text x="1018" y="476" font-size="11" fill="#4338ca" text-anchor="middle">its own workspace only</text>
|
||||
<text x="1018" y="494" font-size="11" fill="#4338ca" text-anchor="middle">A2A still hierarchy-gated</text>
|
||||
|
||||
<!-- side note -->
|
||||
<text x="40" y="568" font-size="11.5" fill="#5b6472">All secrets are encrypted at rest (AES-256-GCM or KMS envelope) and masked on read. The audit ledger records every credential's creation attribution.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,73 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 640" font-family="Inter, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||
<defs>
|
||||
<filter id="sh" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#0b1220" flood-opacity="0.10"/></filter>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#0ea5e9"/></marker>
|
||||
<marker id="ag" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
|
||||
</defs>
|
||||
<rect width="1200" height="640" fill="#fbfcfe"/>
|
||||
<text x="40" y="46" font-size="24" font-weight="700" fill="#15181f">config.yaml → runtime adapter resolution</text>
|
||||
<text x="40" y="72" font-size="13.5" fill="#5b6472">At boot the workspace loads <tspan font-family="monospace" fill="#0369a1">config.yaml</tspan>, selects an adapter by its <tspan font-family="monospace" fill="#0369a1">runtime</tspan>, builds an executor, and registers over A2A. One BaseAdapter contract — drop in any framework.</text>
|
||||
|
||||
<!-- config.yaml -->
|
||||
<g filter="url(#sh)"><rect x="40" y="100" width="330" height="480" rx="13" fill="#1e242e"/></g>
|
||||
<text x="62" y="128" font-size="13" font-weight="700" fill="#e2e8f0" font-family="monospace">config.yaml</text>
|
||||
<g font-family="monospace" font-size="12">
|
||||
<text x="62" y="156" fill="#7dd3fc">name<tspan fill="#cbd5e1">: Content Writer</tspan></text>
|
||||
<text x="62" y="178" fill="#7dd3fc">tier<tspan fill="#cbd5e1">: 2</tspan></text>
|
||||
<text x="62" y="200" fill="#fcd34d">runtime<tspan fill="#cbd5e1">: google-adk</tspan></text>
|
||||
<text x="62" y="222" fill="#7dd3fc">runtime_config<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="84" y="242" fill="#a7f3d0">model<tspan fill="#cbd5e1">: vertex:gemini-2.5-pro</tspan></text>
|
||||
<text x="62" y="266" fill="#7dd3fc">prompt_files<tspan fill="#cbd5e1">: [system-prompt.md]</tspan></text>
|
||||
<text x="62" y="288" fill="#7dd3fc">skills<tspan fill="#cbd5e1">: [seo-research]</tspan></text>
|
||||
<text x="62" y="310" fill="#7dd3fc">tools<tspan fill="#cbd5e1">: [browser] </tspan><tspan fill="#94a3b8"># tier-gated</tspan></text>
|
||||
<text x="62" y="332" fill="#7dd3fc">memory<tspan fill="#cbd5e1">: { scope: team }</tspan></text>
|
||||
<text x="62" y="354" fill="#7dd3fc">a2a<tspan fill="#cbd5e1">: { port: 8000 }</tspan></text>
|
||||
<text x="62" y="376" fill="#7dd3fc">env<tspan fill="#cbd5e1">:</tspan></text>
|
||||
<text x="84" y="396" fill="#a7f3d0">required<tspan fill="#cbd5e1">: [GOOGLE_CLOUD_PROJECT]</tspan></text>
|
||||
</g>
|
||||
<text x="62" y="430" font-size="11" fill="#94a3b8">Hot-reload (live):</text>
|
||||
<text x="62" y="450" font-size="11" fill="#a7f3d0" font-family="monospace">model · skills · tools</text>
|
||||
<text x="62" y="476" font-size="11" fill="#94a3b8">Needs restart / re-provision:</text>
|
||||
<text x="62" y="496" font-size="11" fill="#fca5a5" font-family="monospace">tier · a2a · sub_workspaces</text>
|
||||
<text x="62" y="540" font-size="11" fill="#94a3b8">Model id form:</text>
|
||||
<text x="62" y="560" font-size="11.5" fill="#fcd34d" font-family="monospace">provider:model-id</text>
|
||||
|
||||
<!-- adapter registry -->
|
||||
<path d="M370,300 L432,300" stroke="#0ea5e9" stroke-width="2" fill="none" marker-end="url(#a)"/>
|
||||
<text x="401" y="290" font-size="10.5" font-weight="700" fill="#0369a1" text-anchor="middle">select</text>
|
||||
<g filter="url(#sh)"><rect x="440" y="120" width="300" height="440" rx="13" fill="#f8fafc" stroke="#0ea5e9" stroke-width="1.6"/></g>
|
||||
<text x="590" y="148" font-size="14" font-weight="700" fill="#0369a1" text-anchor="middle">Runtime adapter registry</text>
|
||||
<text x="590" y="168" font-size="10.5" fill="#5b6472" text-anchor="middle">auto-discovered · BaseAdapter contract</text>
|
||||
<g font-size="12" font-weight="600" text-anchor="middle">
|
||||
<rect x="462" y="182" width="256" height="32" rx="7" fill="#fff" stroke="#bae6fd"/><text x="590" y="203" fill="#15181f">claude-code → ClaudeSDKExecutor</text>
|
||||
<rect x="462" y="220" width="256" height="32" rx="7" fill="#fff" stroke="#bae6fd"/><text x="590" y="241" fill="#15181f">langgraph → LangGraphA2AExecutor</text>
|
||||
<rect x="462" y="258" width="256" height="32" rx="7" fill="#fff" stroke="#bae6fd"/><text x="590" y="279" fill="#15181f">crewai · autogen · deepagents</text>
|
||||
<rect x="462" y="296" width="256" height="32" rx="7" fill="#fff" stroke="#bae6fd"/><text x="590" y="317" fill="#15181f">hermes → HermesA2AExecutor</text>
|
||||
<rect x="462" y="334" width="256" height="32" rx="7" fill="#fff" stroke="#bae6fd"/><text x="590" y="355" fill="#15181f">openclaw · gemini-cli (CLI exec)</text>
|
||||
<rect x="462" y="372" width="256" height="32" rx="7" fill="#fff7ed" stroke="#f4b860"/><text x="590" y="393" fill="#b45309">google-adk → GoogleADKA2AExecutor</text>
|
||||
<rect x="462" y="410" width="256" height="32" rx="7" fill="#faf5ff" stroke="#d8b4fe"/><text x="590" y="431" fill="#7c3aed">external → no container (BYO)</text>
|
||||
</g>
|
||||
<text x="590" y="470" font-size="11" fill="#5b6472" text-anchor="middle">contract: setup(config) · create_executor(config)</text>
|
||||
<text x="590" y="490" font-size="11" fill="#5b6472" text-anchor="middle">executor.execute(ctx, event_queue):</text>
|
||||
<text x="590" y="508" font-size="10.5" fill="#5b6472" text-anchor="middle">extract message + history → invoke framework</text>
|
||||
<text x="590" y="524" font-size="10.5" fill="#5b6472" text-anchor="middle">→ write response to A2A event queue</text>
|
||||
<text x="590" y="546" font-size="10.5" fill="#0369a1" text-anchor="middle">MOLECULE_SMOKE_MODE short-circuits I/O</text>
|
||||
|
||||
<!-- boot pipeline -->
|
||||
<path d="M740,300 L802,300" stroke="#64748b" stroke-width="1.8" fill="none" marker-end="url(#ag)"/>
|
||||
<g filter="url(#sh)"><rect x="810" y="120" width="350" height="440" rx="13" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.6"/></g>
|
||||
<text x="985" y="148" font-size="14" font-weight="700" fill="#3730a3" text-anchor="middle">Workspace boot pipeline</text>
|
||||
<g font-size="12" fill="#15181f">
|
||||
<rect x="832" y="166" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="188">load config.yaml + preflight (required env)</text>
|
||||
<rect x="832" y="208" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="230">resolve adapter(runtime) → setup()</text>
|
||||
<rect x="832" y="250" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="272">create_executor() → A2A AgentExecutor</text>
|
||||
<rect x="832" y="292" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="314">assemble system prompt + Agent Card</text>
|
||||
<rect x="832" y="334" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="356">POST /registry/register → online</text>
|
||||
<rect x="832" y="376" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="398">30s heartbeat · skill file-watcher</text>
|
||||
<rect x="832" y="418" width="306" height="34" rx="8" fill="#fff" stroke="#c7cdf5"/><text x="848" y="440">serve A2A (Uvicorn) on a2a.port</text>
|
||||
</g>
|
||||
<text x="985" y="480" font-size="11.5" fill="#4338ca" text-anchor="middle">Preflight FAILS LOUD on a runtime/config or</text>
|
||||
<text x="985" y="498" font-size="11.5" fill="#4338ca" text-anchor="middle">missing-required-env mismatch — never a silent</text>
|
||||
<text x="985" y="516" font-size="11.5" fill="#4338ca" text-anchor="middle">wrong-agent fallback (core#2028).</text>
|
||||
<text x="985" y="544" font-size="10.5" fill="#6366f1" text-anchor="middle">tools gated by tier: browser ≥ T2 · computer ≥ T3</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |