Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ memory, routines and history.
Most AI assistants stop the moment they hit a login screen. Godmode Bot is built around the things a real coworker
needs to be useful:

- **Access** — a managed browser (via [browser-use](https://github.com/browser-use/browser-use)), your Chrome sessions,
and hundreds of apps through [Composio](https://composio.dev) or any MCP server.
- **Access** — a managed browser (via [browser-use](https://github.com/browser-use/browser-use)) and your Chrome sessions.
Agents sign in to websites with your saved logins and 2FA codes, so apps need no MCP connector. Composio and MCP
servers are optional, for instant app triggers and APIs without a website.
- **Credentials without exposure** — a local, encrypted vault for logins and TOTP 2FA. Passwords and codes are typed
into the page *for* the agent; the model never sees them.
- **Autonomy** — powered by [Claude Code](https://code.claude.com) (Opus 5.5) in full-bypass mode, so work continues
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const NAMES: Record<string, string> = {

const POINTS = [
{ icon: Boxes, title: "Hundreds of apps", body: "Gmail, Slack, GitHub, Notion, CRMs, calendars — each becomes a set of tools your agents can call." },
{ icon: ShieldCheck, title: "OAuth, not passwords", body: "You sign in on the app's own page. Tokens live in Composio; Godmode only keeps your API key, encrypted." },
{ icon: ShieldCheck, title: "OAuth sign-in", body: "You sign in on the app's own page. Tokens live in Composio; Godmode only keeps your API key, encrypted." },
{ icon: Layers, title: "Scoped accounts", body: "Connect an account for everyone, one workspace, or a single agent — e.g. work vs. personal Gmail." },
];

Expand All @@ -29,10 +29,10 @@ export function ComposioExplainer() {
<div className="relative grid grid-cols-1 items-center gap-8 @5xl:grid-cols-[1fr_minmax(0,300px)]">
<div>
<p className="eyebrow">Composio</p>
<h3 className="mt-2 text-[22px] leading-tight font-medium tracking-[-0.025em]">Plug your agents into the apps you already use</h3>
<h3 className="mt-2 text-[22px] leading-tight font-medium tracking-[-0.025em]">React the moment something arrives</h3>
<p className="mt-2 max-w-xl text-sm text-muted-foreground">
Composio handles sign-in and API plumbing for hundreds of services. Connect an account once and every agent in reach gets
it as MCP tools — no scraping, no shared passwords.
Optional. Connect an account when an automation should start on a new email or Slack message, or when an agent should call
the app's API directly.
</p>
<div className="mt-6 grid grid-cols-1 gap-3 @3xl:grid-cols-3">
{POINTS.map((p, i) => (
Expand Down
105 changes: 105 additions & 0 deletions apps/desktop/src/components/integrations/no-connectors-note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { useId, useState } from "react";
import { useNavigate } from "react-router";
import { AnimatePresence, motion } from "motion/react";
import { ArrowRight, CircleCheck, Globe, KeyRound, ShieldCheck } from "lucide-react";
import { Button } from "@/components/ui/button";
import { storageKey } from "@/lib/core";

const DISMISS_KEY = storageKey("godmode-integrations-no-connectors");

const STEPS = [
{ icon: Globe, label: "Opens the site" },
{ icon: KeyRound, label: "Fills your login" },
{ icon: ShieldCheck, label: "Adds the 2FA code" },
{ icon: CircleCheck, label: "Signed in as you" },
];

function dismissed(): boolean {
try {
return localStorage.getItem(DISMISS_KEY) === "1";
} catch {
return false;
}
}

/** Integrations are optional: agents sign in to websites with vault logins and 2FA, so apps need no MCP connector. */
export function NoConnectorsNote() {
const navigate = useNavigate();
const [hidden, setHidden] = useState(dismissed);
const titleId = useId();

const dismiss = () => {
try {
localStorage.setItem(DISMISS_KEY, "1");
} catch {
/* ignore */
}
setHidden(true);
};

return (
<AnimatePresence>
{!hidden && (
<motion.section
key="note"
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, height: 0, marginBottom: 0 }}
transition={{ duration: 0.2 }}
className="mb-6 overflow-hidden rounded-xl border border-brand/25 bg-card shadow-card"
aria-labelledby={titleId}
>
<div className="grid grid-cols-1 gap-6 p-5 @4xl:grid-cols-[1fr_minmax(0,280px)] @4xl:items-center @2xl:p-6">
<div className="flex items-start gap-4">
<div className="grid size-10 shrink-0 place-items-center rounded-lg border border-brand/25 bg-brand-soft text-brand-strong">
<ShieldCheck className="size-5" />
</div>
<div className="min-w-0">
<h2 id={titleId} className="text-[15px] leading-snug font-medium tracking-[-0.01em]">Your apps don't need a connector</h2>
<p className="mt-1 max-w-2xl text-sm text-muted-foreground">
Godmode signs in to websites the way you do: with the username, password and 2FA code saved in your Vault. It types them
into the login page itself, so the AI never sees them. Your CRM, a supplier portal, your shop admin: most sites that open in
a browser work right away, without an MCP connector.
</p>
<p className="mt-2 max-w-2xl text-xs leading-relaxed text-muted-foreground">
Connect an app here only when an automation should start the moment something arrives, like a new email, or for an API
without a website.
</p>
<div className="mt-4 flex flex-wrap items-center gap-2">
<Button size="sm" variant="outline" onClick={() => navigate("/vault/logins")}>
Save a login <ArrowRight />
</Button>
<Button size="sm" variant="ghost" className="text-muted-foreground" onClick={dismiss}>
Got it
</Button>
</div>
</div>
</div>
<ol className="hidden rounded-lg border bg-paper-2 p-3 @4xl:block" aria-hidden>
{STEPS.map((s, i) => (
<motion.li
key={s.label}
initial={{ opacity: 0, x: 6 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.08 + i * 0.06, duration: 0.25, ease: [0.2, 0.8, 0.2, 1] }}
className="relative flex items-center gap-2.5 py-1.5 text-xs"
>
<span
className={
i === STEPS.length - 1
? "grid size-6 place-items-center rounded-md border border-brand/25 bg-brand-soft text-brand-strong"
: "grid size-6 place-items-center rounded-md border bg-card text-foreground"
}
>
<s.icon className="size-3.5" />
</span>
<span className={i === STEPS.length - 1 ? "font-medium text-foreground" : "text-muted-foreground"}>{s.label}</span>
</motion.li>
))}
</ol>
</div>
</motion.section>
)}
</AnimatePresence>
);
}
4 changes: 2 additions & 2 deletions apps/desktop/src/components/onboarding/done-step.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { motion } from "motion/react";
import { ArrowRight, Bot, CircleCheck, CircleDashed, Plug, ShieldCheck } from "lucide-react";
import { ArrowRight, Bot, CircleCheck, CircleDashed, KeyRound, ShieldCheck } from "lucide-react";
import { MASCOT_CHARACTER, MASCOT_COLOR, type LicenseState } from "@godmode/shared";
import { Character } from "@/components/character";
import { FormError, SubmitButton } from "./auth-layout";
Expand All @@ -16,8 +16,8 @@ export interface OnboardingSummary {

const NEXT = [
{ to: "/agents/new", icon: <Bot />, title: "Hire your first agent", body: "Pick a template or describe the job." },
{ to: "/vault/logins", icon: <KeyRound />, title: "Save your logins", body: "Agents sign in like you, 2FA included. No connectors needed." },
{ to: "/vault/2fa?import=1", icon: <ShieldCheck />, title: "Import 2FA codes", body: "Scan Google Authenticator exports." },
{ to: "/integrations", icon: <Plug />, title: "Connect your apps", body: "Gmail, Slack, GitHub and more via Composio." },
];

export function DoneStep({
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/lib/mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const EASY_PAGES: Record<string, { title?: string; description?: string }
"/vault/logins": { title: "Passwords", description: "The logins your agents may use. Encrypted on this computer; agents never see the passwords." },
"/vault/2fa": { title: "2FA codes" },
"/vault/cards": { title: "Payment cards" },
"/integrations": { title: "Connected apps", description: "Connect the apps you already use, like Gmail, Slack or Notion, so your agents can work in them." },
"/integrations": { title: "Connected apps", description: "Optional: your agents already sign in to your websites with your saved logins and 2FA codes. Connect an app only so they react the moment something arrives." },
"/messaging": { title: "Chat apps", description: "Talk to your agents from Slack, Telegram or Microsoft Teams." },
"/computer": { title: "Computer control" },
"/ssh": { title: "Servers" },
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src/pages/integrations/integrations-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ApiKeysTab } from "@/components/integrations/api-keys-tab";
import { ApiToolsTab, useApiTools } from "@/components/integrations/api-tools-tab";
import { ComposioTab, useComposioConnections, useComposioStatus } from "@/components/integrations/composio-tab";
import { McpServersTab, useMcpServers } from "@/components/integrations/mcp-servers-tab";
import { NoConnectorsNote } from "@/components/integrations/no-connectors-note";
import { api } from "@/lib/api";
import { qk } from "@/lib/queryKeys";

Expand Down Expand Up @@ -50,9 +51,10 @@ export default function IntegrationsPage() {
<PageHeader
icon={<Plug />}
title="Integrations"
description="Give your agents access to apps and APIs — Composio for hundreds of SaaS apps, tools for any API with a key, MCP servers for anything else."
description="Optional: your agents already sign in to websites with your saved logins and 2FA codes. Add Composio for instant triggers, tools for any API with a key, MCP servers for anything else."
/>
<PageBody>
<NoConnectorsNote />
<Tabs value={tab} onValueChange={setTab} className="gap-6">
<TabsList className="h-10 p-1">
<TabTrigger value="composio" icon={<Boxes />} label="Composio" count={counts.composio} />
Expand Down
5 changes: 3 additions & 2 deletions apps/website/src/components/sections/Capabilities.astro
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ import Character from '../ui/Character.astro';
<div>
<h3 class="h-card">Works with the tools you have.</h3>
<p class="mt-2 text-[15px] leading-relaxed text-muted">
It uses websites and programs the way you do, so there is no coding and no IT project. Connecting Gmail,
Slack or Teams is optional and makes it react the moment something arrives.
No connector per app: it signs in with your own logins and 2FA codes and uses websites and programs the way
you do. No coding, no IT project. Connecting Gmail, Slack or Teams is optional and makes it react the moment
something arrives.
</p>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions apps/website/src/components/sections/Faq.astro
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ const faqs: { key: string; q: string; a: string }[] = [
q: 'Is it really safe to give an AI my passwords?',
a: `Your passwords and 2FA codes live in a vault on your computer, encrypted (AES-256). Godmode types them into the login page itself, so the AI only learns that a password was filled, never what it is, and only on that login’s own website. Every use is logged. One honest exception: on a separate Mac of its own, Godmode controls the whole machine, so signing in there is best effort and off until you allow it.`,
},
{
key: 'connectors',
q: 'Do I need connectors or integrations for my apps?',
a: `No. Many AI assistants need a connector (an “MCP server” or an app integration) for each app before they can work in it. Godmode signs in the way you do, with your own username, password and 2FA code from its encrypted vault, and then works in the website itself. Your CRM, a supplier portal, your shop admin, your accounting tool: most sites that open in your browser work right away, with no connector to set up. Connecting an app is optional and only makes an automation start the moment something arrives, like a new email.`,
},
{
key: 'data',
q: 'Where does my data go?',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/no-connectors/website-faq.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/core/src/runner/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ This run uses ${ctx.glm} on Z.ai, not Claude, for a task Claude couldn't do. It
const where = ctx.vm ? ` It is Google Chrome inside the VM "${ctx.vm.name}", not a browser on ${human}'s computer.` : "";
const takeover = ctx.vm ? "on the VM's screen" : "in Godmode's live browser view";
out.push(`### Browser
Use the \`browser\` MCP tools for anything on the web (navigate, click, type, read pages, take screenshots).${where} The browser keeps its cookies between runs, so you are often already logged in — check before logging in again. ${
Use the \`browser\` MCP tools for anything on the web (navigate, click, type, read pages, take screenshots).${where} The browser keeps its cookies between runs, so you are often already logged in — check before logging in again. A website needs no MCP connector or integration: unless a tool for it is attached, sign in with the vault (see "Logging in to websites") and work in the page. ${
captchaSolverReady(settings)
? `If a CAPTCHA blocks you (reCAPTCHA, Cloudflare Turnstile, a picture with distorted text), call \`captcha_solve\`: ${human}'s solving service solves it and Godmode puts the answer into the page; never try to solve a CAPTCHA yourself. When it can't (hCaptcha, a "Just a moment" page, another kind of puzzle, the daily limit) or another human check blocks you, tell ${human} (they can take over ${takeover}).`
: `If a CAPTCHA or an unexpected human check blocks you, tell ${human} in your final summary (they can take over ${takeover}).`
Expand Down
Loading