Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
e2af497
PMM: update ecosystem-watch — add LangGraph PR verification deferral …
Apr 22, 2026
b44ca60
PMM: add Cloudflare Artifacts positioning brief
Apr 23, 2026
703a7c6
PMM: update EC2 SSH launch brief — social copy APPROVED, TTS audio fi…
Apr 23, 2026
f2f2e87
PMM: update ecosystem-watch — verify LangGraph PRs still OPEN, log PR…
Apr 23, 2026
2f91dc8
docs(marketing): add PR #1702 release note + PR #1686 positioning brief
Apr 23, 2026
9174495
docs(mmm): add Phase 34 positioning one-pager + messaging matrix
Apr 23, 2026
1b47507
docs(pmm): add Issue #1831 positioning brief — Tool Trace + Platform …
Apr 23, 2026
f4a3ff4
docs(marketing): launch brief for PR #1686 Tool Trace + Platform Inst…
Apr 23, 2026
c984b0b
fix(blog): move partner-api-keys to dir/index.md for canonical URL co…
Apr 23, 2026
d6b90c7
docs(marketing): Platform Instructions PMM positioning brief for SMB/…
Apr 23, 2026
5f02091
docs(marketing): Phase 34 GA launch social copy — Tool Trace + Platfo…
Apr 23, 2026
929b5a2
docs(marketing): organize Chrome DevTools MCP social copy + social qu…
Apr 23, 2026
2a51917
docs(marketing): add Tool Trace + Platform Instructions positioning b…
Apr 23, 2026
56ea637
docs(marketing): add Cloudflare Artifacts social copy (Issue #1480)
Apr 23, 2026
93ab7cc
docs(marketing): update social queue status — add Cloudflare Artifacts
Apr 23, 2026
09db6b6
docs(marketing): A2A v1.0 reference story positioning brief — Issue #…
Apr 23, 2026
05bf8ea
docs(marketing): create competitors.md — competitive intelligence tra…
Apr 23, 2026
3b3178c
docs(marketing): Phase 32 SaaS Federation v2 battlecard — multi-tenan…
Apr 23, 2026
e47836d
fix(auth): break infinite redirect loop on /cp/auth/login
HongmingWang-Rabbit Apr 22, 2026
ce0a2f7
fix(auth): redirect to login on 401 from any API call
HongmingWang-Rabbit Apr 22, 2026
6e44ea9
fix(auth): redirect to app.moleculesai.app for login, not tenant subd…
HongmingWang-Rabbit Apr 22, 2026
fe63857
test(auth): provide window.location.pathname in redirectToLogin mocks
Apr 23, 2026
e0ea969
fix(restart): preserve user config volume on default restart (#1822 d…
HongmingWang-Rabbit Apr 23, 2026
4cc6456
feat(a2a): queue-on-busy — Phase 1 of priority queue (#1870)
HongmingWang-Rabbit Apr 23, 2026
7f3e1c3
fix(a2a-queue): use partial-index ON CONFLICT syntax (not constraint …
HongmingWang-Rabbit Apr 23, 2026
05ae6ce
docs(marketing): phase 34 launch prep — battlecard review, SEO fixes,…
Apr 23, 2026
420efd9
docs(marketing): add Phase 34 community announcement
Apr 23, 2026
b5d9939
docs(marketing): add Tool Trace + Platform Instructions social copy
Apr 23, 2026
749ab31
docs(marketing): Phase 34 SEO brief + PMM positioning brief
Apr 23, 2026
0bf283d
docs(social): Apr 30 Phase 34 GA launch copy — Partner API Keys
Apr 23, 2026
1ad5ceb
docs(blog): Tool Trace + Platform Instructions launch blog post (#1835)
Apr 23, 2026
4ef86d7
docs(marketing): batch commit — PMM battlecard, DevRel demos, launch …
Apr 23, 2026
1994c63
docs(seo): MCP server list explainer SEO brief (#1493)
Apr 23, 2026
141392e
docs(marketing): Platform Instructions plan gating — Enterprise-only …
Apr 23, 2026
79c585c
docs(devrel): Cloudflare Artifacts demo package + TTS audio for talk-…
Apr 23, 2026
395c8f8
fix(canvas/config): load runtime+model from workspace metadata + hide…
Apr 23, 2026
ea8dbfc
feat(seo): Phase 34 GA launch brief; MCP server list brief; A2A brief…
Apr 23, 2026
6b91350
docs(seo): A2A enterprise deep-dive brief — slug corrected, approved …
Apr 23, 2026
d673501
docs(social): clean GA language — remove stale Beta/GA option placeho…
Apr 24, 2026
deb621a
docs(community): Phase 34 FAQ + Apr 30 Discord posting runbook
Apr 23, 2026
f921368
docs(marketing): update social queue status — battlecard section added
Apr 23, 2026
325f5ab
docs(community): Phase 34 expanded FAQ + full Discord launch runbook
Apr 23, 2026
a9f1e8c
docs(marketing): three first-pass research files — SaaS Fed v2, rate …
Apr 23, 2026
3238a45
docs(marketing): community announcement SaaS Fed v2 flag + research f…
Apr 23, 2026
aa8dd62
docs/marketing/briefs/pre-launch-blog-qa-notes.md: PMM pre-launch blo…
Apr 23, 2026
b391d64
docs: Phase 34 GA/Beta conflict flagged + SaaS Fed v2 section removed
Apr 23, 2026
8f39969
docs: Phase 34 GA label conflict RESOLVED — GA confirmed for all feat…
Apr 23, 2026
40f9766
docs: Apr 26 social copy — Platform Instructions plan availability co…
Apr 23, 2026
a79e1d0
docs: pre-launch-blog-qa-notes.md — Platform Instructions plan info c…
Apr 23, 2026
6eb2884
docs: SOCIAL-QUEUE-STATUS.md updated 2026-04-24 (T-6 to GA)
Apr 24, 2026
3de44f0
docs: Apr 26 social copy — Platform Instructions PLAN AVAILABILITY CO…
Apr 24, 2026
29b877e
docs: phase-34-community-faq.md — audit log Q&A merged, conflict reso…
Apr 24, 2026
0e5d92b
docs: pre-launch-blog-qa-notes.md — PI plan status updated
Apr 24, 2026
5791ff2
docs: SOCIAL-QUEUE-STATUS.md — Phase 30 campaign archived, Apr 24-25 …
Apr 24, 2026
d9f61d8
docs: Discord runbook + community FAQ — SaaS Fed v2 quick-ref links r…
Apr 24, 2026
5041b5e
docs(marketing): finalize Phase 34 plan availability corrections
Apr 24, 2026
37d5a7a
docs(marketing): mark Apr 26 copy as internally consistent — PI plan …
Apr 24, 2026
0b460cb
docs(marketing): Phase 34 social queue — Apr 26 teaser/copy reconciled
Apr 24, 2026
dd3c684
docs(marketing): replace stale Apr 26 copy with forward-looking teaser
Apr 24, 2026
e1afaef
docs(blog): add Partner API Keys launch post
Apr 24, 2026
2351647
docs(marketing): confirm Partner + Enterprise tier names in onboardin…
Apr 24, 2026
70a5174
docs(marketing): update SOCIAL-QUEUE-STATUS — partner tier confirmed,…
Apr 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions canvas/src/components/AuthGate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export function AuthGate({ children }: { children: ReactNode }) {
setState({ kind: "anonymous", skipRedirect: true });
return;
}
// Never gate /cp/auth/* paths — these ARE the login pages.
if (typeof window !== "undefined" && window.location.pathname.startsWith("/cp/auth/")) {
setState({ kind: "anonymous", skipRedirect: true });
return;
}
let cancelled = false;
fetchSession()
.then((s) => {
Expand Down
54 changes: 52 additions & 2 deletions canvas/src/components/tabs/ConfigTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ interface RuntimeOption {
// Fallback used when /templates can't be fetched (offline, older backend).
// Keep in sync with manifest.json workspace_templates as a defensive default.
// Model + env suggestions only flow when the backend is reachable.
// Runtimes that manage their own config outside the platform's config.yaml
// template. For these, a missing config.yaml is expected — the user manages
// config via the runtime's own mechanism (e.g. hermes edits
// ~/.hermes/config.yaml on the workspace EC2 via the Terminal tab or its
// own CLI). Showing a "No config.yaml found" error for these is misleading.
const RUNTIMES_WITH_OWN_CONFIG = new Set<string>(["hermes", "external"]);

const FALLBACK_RUNTIME_OPTIONS: RuntimeOption[] = [
{ value: "", label: "LangGraph (default)", models: [] },
{ value: "claude-code", label: "Claude Code", models: [] },
Expand Down Expand Up @@ -134,14 +141,50 @@ export function ConfigTab({ workspaceId }: Props) {
const loadConfig = useCallback(async () => {
setLoading(true);
setError(null);

// ALWAYS load workspace metadata first (runtime + model). These are the
// source of truth regardless of whether the runtime uses our config.yaml
// template. Without this the form falls back to empty/default values on
// a hermes workspace (which doesn't use our template), creating the
// appearance that the saved runtime is unset — and worse, clicking Save
// would silently flip `runtime` from `hermes` back to the dropdown
// default `LangGraph`. See GH #1894.
let wsMetadataRuntime = "";
let wsMetadataModel = "";
try {
const ws = await api.get<{ runtime?: string }>(`/workspaces/${workspaceId}`);
wsMetadataRuntime = (ws.runtime || "").trim();
} catch { /* fall back to config.yaml */ }
try {
const m = await api.get<{ model?: string }>(`/workspaces/${workspaceId}/model`);
wsMetadataModel = (m.model || "").trim();
} catch { /* non-fatal */ }

try {
const res = await api.get<{ content: string }>(`/workspaces/${workspaceId}/files/config.yaml`);
const parsed = parseYaml(res.content);
setOriginalYaml(res.content);
setRawDraft(res.content);
setConfig({ ...DEFAULT_CONFIG, ...parsed } as ConfigData);
// Merge: config.yaml wins for fields it declares, but workspace metadata
// wins for runtime + model when config.yaml doesn't set them.
const merged = { ...DEFAULT_CONFIG, ...parsed } as ConfigData;
if (!merged.runtime && wsMetadataRuntime) merged.runtime = wsMetadataRuntime;
if (!merged.model && wsMetadataModel) merged.model = wsMetadataModel;
setConfig(merged);
} catch {
setError("No config.yaml found");
// No platform-managed config.yaml. Some runtimes (hermes, external)
// manage their own config outside this template; that's expected, not
// an error. Populate the form from workspace metadata so the user
// still sees the saved runtime + model.
const runtimeManagesOwnConfig = RUNTIMES_WITH_OWN_CONFIG.has(wsMetadataRuntime);
if (!runtimeManagesOwnConfig) {
setError("No config.yaml found");
}
setConfig({
...DEFAULT_CONFIG,
runtime: wsMetadataRuntime,
model: wsMetadataModel,
} as ConfigData);
} finally {
setLoading(false);
}
Expand Down Expand Up @@ -511,6 +554,13 @@ export function ConfigTab({ workspaceId }: Props) {
{error && (
<div className="mx-3 mb-2 px-3 py-1.5 bg-red-900/30 border border-red-800 rounded text-xs text-red-400">{error}</div>
)}
{!error && RUNTIMES_WITH_OWN_CONFIG.has(config.runtime || "") && (
<div className="mx-3 mb-2 px-3 py-1.5 bg-zinc-900/50 border border-zinc-700 rounded text-xs text-zinc-400">
{config.runtime === "hermes"
? "Hermes manages its own config at ~/.hermes/config.yaml on the workspace host. Edit it via the Terminal tab or the hermes CLI, not this form."
: "This runtime manages its own config outside the platform template."}
</div>
)}
{success && (
<div className="mx-3 mb-2 px-3 py-1.5 bg-green-900/30 border border-green-800 rounded text-xs text-green-400">Saved</div>
)}
Expand Down
14 changes: 12 additions & 2 deletions canvas/src/lib/__tests__/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ describe("redirectToLogin", () => {
const href = "https://acme.moleculesai.app/dashboard";
Object.defineProperty(window, "location", {
writable: true,
value: { href },
value: {
href,
pathname: "/dashboard",
hostname: "acme.moleculesai.app",
protocol: "https:",
},
});
redirectToLogin("sign-in");
// href now holds the redirect target. encodeURIComponent(href) must
Expand All @@ -61,7 +66,12 @@ describe("redirectToLogin", () => {
it("uses signup path for sign-up screenHint", () => {
Object.defineProperty(window, "location", {
writable: true,
value: { href: "https://acme.moleculesai.app/" },
value: {
href: "https://acme.moleculesai.app/",
pathname: "/",
hostname: "acme.moleculesai.app",
protocol: "https:",
},
});
redirectToLogin("sign-up");
expect((window.location as unknown as { href: string }).href).toContain("/cp/auth/signup");
Expand Down
7 changes: 7 additions & 0 deletions canvas/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ async function request<T>(
credentials: "include",
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
});
if (res.status === 401) {
// Session expired or credentials lost — redirect to login once.
// Import dynamically to avoid circular dependency with auth.ts.
const { redirectToLogin } = await import("./auth");
redirectToLogin("sign-in");
throw new Error("Session expired — redirecting to login");
}
if (!res.ok) {
const text = await res.text();
throw new Error(`API ${method} ${path}: ${res.status} ${text}`);
Expand Down
20 changes: 19 additions & 1 deletion canvas/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* can surface them.
*/
import { PLATFORM_URL } from "./api";
import { SaaSHostSuffix } from "./tenant";

export interface Session {
user_id: string;
Expand All @@ -17,6 +18,18 @@ export interface Session {
// Base path prefix for auth endpoints on the control plane.
const AUTH_BASE = "/cp/auth";

// Auth UI lives on the "app" subdomain (app.moleculesai.app), NOT on
// tenant subdomains (hongmingwang.moleculesai.app). Tenant subdomains
// proxy to EC2 platform which has no auth routes.
function getAuthOrigin(): string {
if (typeof window === "undefined") return PLATFORM_URL;
const host = window.location.hostname;
if (host.endsWith(SaaSHostSuffix)) {
return `${window.location.protocol}//app${SaaSHostSuffix}`;
}
return PLATFORM_URL;
}

/**
* fetchSession probes /cp/auth/me with the session cookie (credentials:
* include mandatory cross-origin). Returns the Session on 200, null on
Expand Down Expand Up @@ -44,8 +57,13 @@ export async function fetchSession(): Promise<Session | null> {
*/
export function redirectToLogin(screenHint: "sign-up" | "sign-in" = "sign-in"): void {
if (typeof window === "undefined") return;
// Guard against infinite redirect loop: if we're already on the login
// page, don't redirect again (each redirect double-encodes return_to
// until the URL exceeds header limits → 431).
if (window.location.pathname.startsWith("/cp/auth/")) return;
const returnTo = window.location.href;
const path = screenHint === "sign-up" ? "signup" : "login";
const dest = `${PLATFORM_URL}${AUTH_BASE}/${path}?return_to=${encodeURIComponent(returnTo)}`;
const authOrigin = getAuthOrigin();
const dest = `${authOrigin}${AUTH_BASE}/${path}?return_to=${encodeURIComponent(returnTo)}`;
window.location.href = dest;
}
1 change: 1 addition & 0 deletions docs/blog/2026-04-20-chrome-devtools-mcp-seo/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ date: 2026-04-20
slug: browser-automation-ai-agents-mcp
description: "Learn how to add browser automation to your AI agents using Chrome DevTools and the Model Context Protocol. Full Python code examples — no Puppeteer wrappers, no SaaS dependencies."
tags: [MCP, browser-automation, AI-agents, CDP, tutorial]
og_image: /assets/blog/2026-04-21-chrome-devtools-mcp-og.png
---

# Give Your AI Agent a Real Browser: MCP + Chrome DevTools
Expand Down
1 change: 1 addition & 0 deletions docs/blog/2026-04-20-chrome-devtools-mcp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ date: 2026-04-20
slug: chrome-devtools-mcp
description: "Chrome DevTools MCP gives any compatible AI agent full browser control through a standards-based interface. That's powerful for prototypes. For production, you need a governance layer. Here's where Molecule AI fits in."
tags: [browser-automation, mcp, governance, chrome-devtools, security]
og_image: /assets/blog/2026-04-21-chrome-devtools-mcp-og.png
---

# Browser Automation Meets Production Standards
Expand Down
3 changes: 2 additions & 1 deletion docs/blog/2026-04-21-cloudflare-artifacts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ date: 2026-04-21
slug: cloudflare-artifacts-molecule-ai
description: "Attach a Cloudflare Artifacts git repository to any Molecule AI workspace. Import existing repos, fork for experiments, mint short-lived git credentials — all via the platform API. Git-native storage for AI agents."
tags: [Cloudflare, git, artifacts, AI-agents, workflow, tutorial]
status: "⚠️ PM ruling 2026-04-22: sub-100ms claim UNSUBSTANTIATED — replaced with 'low-latency' (same latency class)"
---

# Give Your AI Agent a Git Repository: Molecule AI + Cloudflare Artifacts
Expand All @@ -25,7 +26,7 @@ Git-native storage is different because:
- **Agents already know git.** Clone, branch, commit, push. No new primitives to learn.
- **Versioning is structural.** Every change is a commit. Rollback is `git revert`. No "last writer wins" data loss.
- **Collaboration is native.** Fork a repo, experiment, open a PR. The same workflow humans use to collaborate applies to agents.
- **Cloudflare Artifacts is fast.** Git operations run on Cloudflare's edge — sub-100ms clone times from anywhere. No S3 bandwidth bills.
- **Cloudflare Artifacts is fast.** Git operations run on Cloudflare's edge — low-latency clone times from anywhere. No S3 bandwidth bills.
- **Access control is git-native.** Token scoping, branch protection, repo-level permissions. The same model your team already uses.

## API Reference
Expand Down
4 changes: 3 additions & 1 deletion docs/blog/2026-04-22-a2a-v1-agent-platform/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: "What A2A v1.0 Means for Your Agent Stack: Why Protocol-Native Beats Prot
description: "A2A v1.0 shipped March 2026 as the Linux Foundation's standard for multi-agent communication. Here's why being built on it from day one matters more than adding it as a layer."
date: 2026-04-22
canonical: https://docs.molecule.ai/blog/a2a-v1-agent-platform
tags: [a2a, agent-protocol, multi-agent, governance, enterprise, platform]
og_image: /assets/blog/2026-04-21-chrome-devtools-mcp-og.png
---

*Meta description (160 chars): Before you buy an agent platform, ask how A2A delegation is attributed. The answer reveals everything about governance.*
Expand Down Expand Up @@ -49,7 +51,7 @@ Both Python and Node.js external agent templates are under 100 lines. Registrati

## Why This Matters Now: The Governance Gap in Competing Implementations

A2A v1.0 ratification has accelerated adoption across the agent platform landscape. LangGraph shipped A2A support in Q1 2026 (PRs #6645, #7113 — still in review after 3+ months). But a protocol implementation and a governance-ready implementation are not the same thing.
A2A v1.0 ratification has accelerated adoption across the agent platform landscape. LangGraph's A2A implementation (PRs #6645, #7113 — ⚠️ VERIFY: PMM 2026-04-21 confirmed these PRs not found in langchain-ai/langgraph open PR list; may be merged, closed, or re-numbered) positions against the governance gap. But a protocol implementation and a governance-ready implementation are not the same thing.

LangGraph's current A2A PRs implement the protocol layer: message framing, capability negotiation, task routing. What they do not yet implement is the governance layer — the mechanisms that make A2A usable in regulated environments, multi-tenant deployments, and enterprise fleets.

Expand Down
1 change: 1 addition & 0 deletions docs/blog/2026-04-22-cloudflare-tunnel-migration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ date: 2026-04-22
slug: cloudflare-tunnel-migration
description: "Phase 33 replaces Cloudflare Tunnel with direct-connect agent workspaces that get their own public IPs. Here's what changed, why, and what it means for your deployment."
tags: [platform, infrastructure, cloud, deployment]
og_image: /assets/blog/2026-04-21-chrome-devtools-mcp-og.png
---

# Phase 33: From Cloudflare Tunnel to Direct Connect — How Molecule AI Agent Workspaces Get Their Own IP
Expand Down
75 changes: 75 additions & 0 deletions docs/blog/2026-04-22-cloudflare-tunnel-migration/social-copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Cloudflare Tunnel Migration — Social Copy
Campaign: Phase 33 direct-connect | Source: PR #1612
Publish day: 2026-04-22
Status: DRAFT — for Social Media Brand review + publish
Blog: `docs.moleculesai.app/blog/cloudflare-tunnel-migration` (pending)

---

## X (Twitter) — 4-post thread

### Post 1 — Hook
Your agent workspace has a new IP address.

In Phase 33, every Molecule AI workspace in your cloud account gets its own public IP — direct-connect, no Cloudflare Tunnel in the path.

That's a real change for how you run production agents.

---

### Post 2 — What changed
Before Phase 33: every workspace connected through Cloudflare Tunnel (cloudflared).
Outbound-only, no firewall rules needed. But: extra latency, egress metered by Cloudflare, single dependency.

After Phase 33: each workspace gets a VPC public IP. The platform connects directly.
Same security model, cleaner path.

---

### Post 3 — The operational wins
Direct-connect workspaces mean:
→ curl the IP directly — no tunnel diagnostic dance
→ no Cloudflare egress costs at agent-fleet scale
→ no single dependency on Cloudflare edge availability
→ platform-controlled inbound rules via AWS security groups

If you're running 10+ production agent workspaces, this compounds.

---

### Post 4 — CTA
Phase 33 is live for all new cloud-hosted workspaces.

Works with existing Molecule AI deployments — no config changes required.
Existing tunnel workspaces continue to work; direct-connect is the default for new provisions.

→ [docs link]

---

## LinkedIn — Single post

**Title:** We replaced Cloudflare Tunnel with direct-connect agent workspaces. Here's what changed.

When you run a cloud-hosted agent workspace, there are two ways it can connect to the platform:

The old way: a lightweight daemon (Cloudflare Tunnel / cloudflared) runs inside the container, maintaining an outbound-only WebSocket to Cloudflare's edge. No inbound firewall rules required. Clean and simple — until you're running 20 agents at scale.

That's the model Phase 33 replaces.

Every new workspace in your cloud account now gets its own public IP from the VPC public subnet. The platform connects directly, with the same authentication and security model. No tunnel in the path.

The operational differences matter at scale:
- **No egress costs** through Cloudflare's metered network — the workspace sends traffic directly from your VPC
- **Lower latency** — one fewer network hop through Cloudflare's edge
- **Direct diagnostics** — curl the IP, run network checks, SSH directly — no tunnel to debug
- **No single dependency** — if Cloudflare has an incident, your agents keep running

For single-agent dev environments, the tunnel model was fine. For production agent fleets, direct-connect is the right trade-off.

Phase 33 is live for all new cloud-hosted workspaces. Existing tunnel workspaces continue to function; direct-connect is the default going forward.

→ [Read the architecture walkthrough](https://docs.molecule.ai/docs/guides/remote-workspaces)
→ [Molecule AI on GitHub](https://github.com/Molecule-AI/molecule-core)

#DevOps #CloudComputing #AIAgents #AWS #MoleculeAI
Loading
Loading