Repository navigation
Add Teams landing page and Cloud signup handoff #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
3112f77
feat(web): add Teams landing and Cloud signup handoff
willwashburn cc0df75
Remove unlaunched Teams onboarding compatibility routes
willwashburn 3476b7b
Add Teams social card with coding agents
willwashburn c0d0ad4
Clarify automatic session sharing on Teams landing
willwashburn 97dccbf
Simplify Teams session overview heading
willwashburn 6c55de5
Add Teams collaboration context above messaging bullets
willwashburn 59a5038
Unify Teams signup button labels
willwashburn fb99384
Replace secondary Teams CTA with credit card note
willwashburn 31bc4cd
Identify Google authentication in Teams signup buttons
willwashburn 6d72baf
Simplify Teams signup buttons to Sign up for free
willwashburn 7171635
Trim trailing stylesheet whitespace
willwashburn fe07da6
Clarify when agents collaborate on Teams work
willwashburn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Teams dashboard concept | ||
|
|
||
| Asset: `web/public/teams/teams-dashboard-concept.png` (1585 × 992). | ||
|
|
||
| Created using the built-in imagegen tool. This is a product concept with example | ||
| sessions, not a screenshot of a connected account. The image links to its full-size | ||
| version from the Teams landing page. | ||
|
|
||
| ## Design brief | ||
|
|
||
| A flat navy desktop interface with one session table grouped by the human running | ||
| the agents. Columns: Session, Tool, Status, Pull request, Updated. Statuses are | ||
| Working, Idle, and Finished; only finished sessions have PR links. The important | ||
| columns sit before Updated so they remain visible in the landing page's right crop. | ||
|
|
||
| | Teammate | Session | Tool | Status | PR | | ||
| | --- | --- | --- | --- | --- | | ||
| | Will Washburn | Add Google sign-in | Claude Code | Working | | | ||
| | Will Washburn | Improve onboarding copy | Codex | Idle | | | ||
| | Will Washburn | Fix duplicate uploads | Claude Code | Finished | #482 | | ||
| | Maya Chen | Build sessions search | Codex | Working | | | ||
| | Maya Chen | Review retry handling | Gemini CLI | Idle | | | ||
| | Maya Chen | Add team invitations | Claude Code | Finished | #487 | | ||
| | Alex Rivera | Audit session sharing | Claude Code | Working | | | ||
| | Alex Rivera | Update setup guide | OpenCode | Finished | #491 | | ||
|
|
||
| ## Surface cleanup prompt | ||
|
|
||
| Edit this Agent Relay Teams dashboard screenshot. Preserve the exact layout, | ||
| dimensions, all text, all eight rows, all three human groups, status dots, and all | ||
| PR numbers. Change ONLY the surface rendering. The current image has strange | ||
| black/blue/green mottled patches and waves in the background and behind rows. | ||
| Remove EVERY such artifact. Make the ENTIRE screenshot fully opaque, perfectly | ||
| flat, clean digital UI. Every background surface must be a solid uniform navy | ||
| color: page #0b1c2a, top bar #102536, group headers #132b3c, session rows #0e2333, | ||
| subtle first-row highlight #18394f. Thin solid separators. Absolutely NO | ||
| transparency, no black cut-out holes, no gradients, no grain, no glow, no textures, | ||
| no ripples, no smoke, no shadows. This is a pixel-sharp product screenshot of a | ||
| normal flat application, not an artistic treatment. Keep text and icons crisp | ||
| with clean antialiasing and excellent contrast. Small status dots remain blue for | ||
| Working, amber for Idle, green for Finished. Preserve all exact existing content. | ||
|
|
||
| ## Branding correction prompt | ||
|
|
||
| Built-in imagegen edit using the existing dashboard as the target and | ||
| `web/public/brand-kit/agent-relay-logo-horizontal-transparent.png` as the | ||
| authoritative branding reference. | ||
|
|
||
| Use case: compositing. | ||
| Input image 1: edit target, the existing Agent Relay sessions dashboard concept. | ||
| Input image 2: authoritative logo insert from the repository's brand kit, agent-relay-logo-horizontal-transparent.png. | ||
| Replace ONLY the incorrect top-left text logo in image 1 with the EXACT real horizontal logo from image 2: the two interlocking rounded blue diamond/chevron shapes (bright sky-blue left shape, darker blue right shape) and the white lowercase agentrelay wordmark with its specific original letterforms. Composite the provided branding, do not invent or redesign the symbol or typeset a substitute. The input logo has large transparent margins: ignore those margins and use only the visible logo artwork. Fit the complete real lockup at about x=28..180, y=22..47 within the existing top bar, centered vertically; preserve the logo's original aspect ratio. Retain the existing divider around x=211 and the AgentWorkforce workspace selector. | ||
| Preserve all other pixels and layout as closely as possible: original 1585x992 canvas, navy backgrounds, all navigation, all text, table rows, three human groups, tool icons, statuses, PR numbers, and separators. No added ornamentation. No new elements. Final result must be a crisp screenshot with the actual supplied Agent Relay brand lockup in the top left. | ||
|
|
||
| ## Final logo spacing prompt | ||
|
|
||
| Built-in imagegen edit to increase the separation between the mark and wordmark | ||
| at the landing page's displayed image size. | ||
|
|
||
| Use case: precise-object-edit. | ||
| Edit only the spacing in the Agent Relay logo at the TOP LEFT of this existing dashboard screenshot. | ||
| The blue symbol currently ends around x=78 and the white wordmark begins around x=82. Increase that 4px gap to a clear 16px gap by shifting ONLY the entire white "agentrelay" wordmark about 12 pixels to the right, so it starts around x=94 and ends around x=227. Keep the blue symbol in its current location and at its current size, about x=34..78. Keep the divider at x=244. Keep the exact existing official blue symbol shape and exact existing white wordmark letterforms, height, weight, and baseline. Do not redesign or typeset new branding. The symbol and wordmark should feel separate with comfortable breathing room even when this screenshot is displayed at half size. | ||
| Everything else is invariant: same 1585x992 canvas, same header positions, workspace selector, navigation, backgrounds, all table rows, text, statuses, tool icons, and PR numbers. Make no other visual changes. Preserve the rest of the screenshot. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Teams entry into Cloud | ||
|
|
||
| The marketing `/teams` signup buttons link directly to Cloud's Google auth | ||
| endpoint, `/cloud/api/auth/google/start?next=%2Fteams%2Fconnect`. They use a | ||
| full browser navigation so Cloud can set OAuth cookies and redirect to Google. | ||
| The post-auth `/teams/connect` destination preserves Teams signup attribution | ||
| and then redirects to `/cloud/dashboard`. | ||
|
|
||
| Cloud handles Google auth and sends the user to `/cloud/dashboard`. Accounts | ||
| created through this Teams flow are marked directly on Cloud's `users` table | ||
| with `signup_source = teams` and `dashboard_version = 2`. They see the new Hello | ||
| world dashboard. Existing accounts keep their current dashboard, including | ||
| when signing in through the Teams link. The assignment persists across logins. | ||
| The migration adds both columns without changing existing user data; existing | ||
| accounts default to version `1` with an unknown (NULL) signup source. | ||
|
|
||
| ## Local development | ||
|
|
||
| In the Cloud companion checkout, run `npm run dev:local` (see its | ||
| `docs/local-teams.md`). Here, run `npm run dev:teams`. Open | ||
| `http://127.0.0.1:3100/teams`. The development-only `/cloud/*` proxy forwards to | ||
| Cloud at `127.0.0.1:3101`, preserving one origin for API requests and auth cookies. | ||
| Keep `NEXT_PUBLIC_CLOUD_URL` unset. | ||
|
|
||
| Google needs a development OAuth client with the exact callback | ||
| `http://127.0.0.1:3100/cloud/api/auth/callback/google`. Without it, visit | ||
| `http://127.0.0.1:3100/cloud/api/auth/dev-login?source=teams` to create a separate | ||
| local Teams signup. The test login without `source=teams` retains the original | ||
| local account for testing the existing dashboard. | ||
|
|
||
| The Cloud companion owns cohort persistence, dashboard routing, and all future | ||
| setup functionality. V2 intentionally contains only Hello world for now. Its | ||
| migration must land before the runtime change under the existing reviewed PR | ||
| and human release gates. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/usr/bin/env node | ||
| import { copyFile, mkdir, readFile, writeFile, chmod } from 'node:fs/promises'; | ||
| import { createHash } from 'node:crypto'; | ||
| import { resolve, dirname, isAbsolute } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { parseArgs } from 'node:util'; | ||
| const { values } = parseArgs({ options: { binary: { type: 'string' }, platform: { type: 'string' } } }); | ||
| if (!values.binary || !isAbsolute(values.binary) || !/^(darwin|linux)-(arm64|x64)$/.test(values.platform ?? '')) { | ||
| throw new Error('Use --binary /absolute/native-binary --platform darwin-arm64 (or supported linux/macOS variant).'); | ||
| } | ||
| const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); | ||
| const destination = resolve(root, 'web/public/downloads/agent-relay-probe', values.platform); | ||
| const bytes = await readFile(values.binary); | ||
| await mkdir(destination, { recursive: true }); | ||
| await copyFile(values.binary, resolve(destination, 'agent-relay-probe')); | ||
| await chmod(resolve(destination, 'agent-relay-probe'), 0o755); | ||
| await writeFile(resolve(destination, 'agent-relay-probe.sha256'), createHash('sha256').update(bytes).digest('hex') + ' agent-relay-probe\n'); | ||
| console.log('Staged native probe and SHA-256 for local website testing.'); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| import { ContextCapabilities } from '../../components/home/ContextCapabilities'; | ||
| import type { Metadata } from 'next'; | ||
| import Image from 'next/image'; | ||
| import dashboardConcept from '../../public/teams/teams-dashboard-concept.png'; | ||
| import sessionConcept from '../../public/teams/teams-session-overview-concept.png'; | ||
| import { HeroTerminalMarquee } from '../../components/home/HeroTerminalMarquee'; | ||
| import { DeploymentCall } from '../../components/home/DeploymentCall'; | ||
| import { MessagingFeature } from '../../components/home/MessagingFeature'; | ||
| import { DurableWorkflowFeature } from '../../components/home/DeliveryFeature'; | ||
| import { InvestorStrip } from '../../components/InvestorStrip'; | ||
| import { GitHubIcon, WaveDivider } from '../../components/home/icons'; | ||
| import { SiteNav } from '../../components/SiteNav'; | ||
| import { SiteFooter } from '../../components/SiteFooter'; | ||
| import { TEAMS_OG_ALT, TEAMS_OG_IMAGE_PATH, ogImage } from '../../lib/og-meta'; | ||
| import { absoluteUrl } from '../../lib/site'; | ||
| import { teamsCloudUrl } from '../../lib/teams-cloud'; | ||
| import home from '../landing.module.css'; | ||
| import flows from '../flows/flows.module.css'; | ||
| import { IntegrationMarquee } from '../flows/IntegrationMarquee'; | ||
| import s from './teams-landing.module.css'; | ||
|
|
||
| export const metadata: Metadata = { | ||
| title: 'Agent Relay Teams | Your team’s coding sessions', | ||
| description: 'Connect your computer to Agent Relay and bring your team’s coding sessions into one shared history.', | ||
| alternates: { canonical: absoluteUrl('/teams') }, | ||
| openGraph: { | ||
| title: 'Agent Relay Teams | Your team’s coding sessions', | ||
| description: 'See what every agent is doing. Follow the work. Share what works.', | ||
| url: absoluteUrl('/teams'), | ||
| type: 'website', | ||
| images: [ogImage(TEAMS_OG_IMAGE_PATH, TEAMS_OG_ALT)], | ||
| }, | ||
| twitter: { | ||
| card: 'summary_large_image', | ||
| title: 'Agent Relay Teams | Your team’s coding sessions', | ||
| description: 'See what every agent is doing. Follow the work. Share what works.', | ||
| images: [absoluteUrl(TEAMS_OG_IMAGE_PATH)], | ||
| }, | ||
| }; | ||
|
|
||
| export default function TeamsPage() { | ||
| const signupHref = teamsCloudUrl('/api/auth/google/start?next=%2Fteams%2Fconnect'); | ||
| const signupLabel = 'Sign up for free'; | ||
| const setupLink = ( | ||
| <a className={`${home.ctaPrimary} ${home.homeNavAction}`} href={signupHref}> | ||
| {signupLabel} | ||
| </a> | ||
| ); | ||
|
|
||
| return ( | ||
| <div className={`${flows.page} ${home.messagingPage} ${s.page}`}> | ||
| <a className="skip-link" href="#main">Skip to content</a> | ||
| <SiteNav hideLinks actions={setupLink} mobileMenuContent={setupLink} /> | ||
|
|
||
| <main id="main"> | ||
| <div className={home.heroSection}> | ||
| <section className={home.heroCenter}> | ||
| <div className={home.heroCenterColumn}> | ||
| <h1 className={`${home.headline} ${home.heroCenterHeadline}`}> | ||
| <span className={flows.headlineLine}>See what every agent on your team is doing</span> | ||
| </h1> | ||
| <p className={`${home.subtitle} ${home.heroCenterSubtitle}`}> | ||
| Share your coding agent sessions with your team, find overlapping work, and discover whats working for everyone. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Correct the public copy.
🤖 Prompt for AI Agents |
||
| </p> | ||
| <div className={`${home.heroCenterCtas} ${s.signupCtas}`}> | ||
| <a className={home.ctaPrimary} href={signupHref}> | ||
| {signupLabel} | ||
| </a> | ||
| <p className={s.signupNote}>No credit card required</p> | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <InvestorStrip /> | ||
| <HeroTerminalMarquee showAvatars /> | ||
| </div> | ||
|
|
||
| <div className={flows.main}> | ||
|
|
||
| <div className={flows.capabilityWaveBreak}><WaveDivider variant="capability" /></div> | ||
|
|
||
| <section id="how-it-works" className={`${flows.sectionBand} ${flows.bandCode} ${s.activitySection}`} aria-labelledby="teams-setup-heading"> | ||
| <div className={s.activityIntro}> | ||
| <h2 id="teams-setup-heading">Your whole team's coding agents, under one roof</h2> | ||
| <p>Work like you normally would. Agent sessions get shared automatically. Get a bird’s-eye view of all the work happening across the team.</p> | ||
| </div> | ||
| <figure className={s.productScreenshot}> | ||
| <a href={dashboardConcept.src} target="_blank" rel="noreferrer" aria-label="View the full dashboard concept"> | ||
| <Image | ||
| src={dashboardConcept} | ||
| width={1585} | ||
| height={992} | ||
| sizes="(max-width: 960px) 100vw, 950px" | ||
| alt="Dashboard concept: eight coding sessions grouped under Will, Maya, and Alex, with coding tools, Working, Idle, and Finished statuses, and pull request links on finished sessions." | ||
| /> | ||
| </a> | ||
| </figure> | ||
| </section> | ||
|
|
||
| <div className={flows.capabilityWaveBreak}><WaveDivider variant="capability" /></div> | ||
|
|
||
| <section id="session-overview" className={`${flows.sectionBand} ${s.sessionSection}`} aria-labelledby="session-overview-heading"> | ||
| <div className={s.sessionIntro}> | ||
| <h2 id="session-overview-heading">Dig in when you need to</h2> | ||
| <p>Open any agent session to see what it’s working toward, the constraints it’s following, and how long it’s been running. Read the conversation, or replay it from the start.</p> | ||
| </div> | ||
| <figure className={s.sessionScreenshot}> | ||
| <a href={sessionConcept.src} target="_blank" rel="noreferrer" aria-label="View the full session detail concept (opens in a new tab)"> | ||
| <Image | ||
| src={sessionConcept} | ||
| sizes="(max-width: 960px) 100vw, 950px" | ||
| alt="Session detail concept for Add Google sign-in: an intent and constraints overview, Working status, running time of 18 minutes 42 seconds, a Replay conversation button, and the rendered conversation between Will Washburn and Claude Code." | ||
| /> | ||
| </a> | ||
| </figure> | ||
| </section> | ||
|
|
||
| <div className={flows.capabilityWaveBreak}><WaveDivider variant="capability" /></div> | ||
|
|
||
| <section id="teams-durable-workflows" className={flows.workflowSection} aria-label="Find the shared bottlenecks. Fix with workflows."> | ||
| <DurableWorkflowFeature | ||
| title="Find the shared bottlenecks. Fix with workflows." | ||
| showCapabilities={false} | ||
| items={[ | ||
| 'Turn recurring reviews, handoffs, and follow-ups into workflows your whole team can reuse.', | ||
| 'Bring agents, scripts, and human approvals together in a clear sequence of steps.', | ||
| 'Run workflows on a schedule or when work changes in your connected tools.', | ||
| 'See where work gets stuck, improve the process, and share what works across the team.', | ||
| ]} | ||
| /> | ||
| </section> | ||
|
|
||
| <div className={flows.capabilityWaveBreak}><WaveDivider variant="capability" /></div> | ||
|
|
||
| <section id="teams-agent-workflows" className={flows.workflowSection} aria-label="Let your agents talk. Directly."> | ||
| <MessagingFeature intro="Work together on the intents and constraints, but let the agents collaborate themselves when it’s time to do the work." /> | ||
| </section> | ||
|
|
||
| <section id="how-it-works-more" aria-label="Agents on the Relay have everything they need to collaborate"> | ||
| <ContextCapabilities title="Agents on the Relay have everything they need to collaborate" /> | ||
| </section> | ||
|
|
||
| <section className={`${flows.sectionBand} ${flows.openSourceSection}`} aria-labelledby="teams-open-source"> | ||
| <div className={flows.sectionIntro}> | ||
| <h2 id="teams-open-source">Open source.<br />Run it anywhere.</h2> | ||
| <p> | ||
| Your laptop, your servers, or our cloud. Agent Relay runs where your work lives, | ||
| with the source code in your hands. | ||
| </p> | ||
| <div className={flows.ctaRow}> | ||
| <a href="https://github.com/agentworkforce/relay" className={flows.ctaSecondary}> | ||
| <GitHubIcon /> | ||
| Github | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <div className={flows.capabilityWaveBreak}><WaveDivider variant="capability" /></div> | ||
|
|
||
| <section className={`${flows.sectionBand} ${flows.bandIntegrations} ${s.integrationsSection}`}> | ||
| <div className={flows.sectionIntro}> | ||
| <h2>Connect the tools you already use.</h2> | ||
| <p> | ||
| Give all the agents on the relay controlled access to the tools they need through a virtual file system. | ||
| </p> | ||
| </div> | ||
|
|
||
| <IntegrationMarquee /> | ||
| </section> | ||
|
|
||
| <DeploymentCall | ||
| title="Scope your Agent Relay deployment" | ||
| example="agent" | ||
| description="We're actively looking for design partners who are looking to level their engineering team's process up. You'll have direct access to our team and great discounts on all paid plans." | ||
| topics={[ | ||
| 'Walk through how to get your team and their agents on the relay.', | ||
| 'Discover where you can level up your agents and workflows', | ||
| 'Identify team wide bottlenecks and discover proactive workflows to run on the relay', | ||
| 'Review hosted, private cloud, or self-managed options', | ||
| 'Leave with a clear path from discovery to production', | ||
| ]} | ||
| contact={{ name: 'Will Washburn', role: 'Co-founder, CEO', image: '/authors/will.png', href: '/will' }} /> | ||
| </div> | ||
| </main> | ||
|
|
||
| <SiteFooter /> | ||
| </div> | ||
| ); | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🟠 Major | 🏗️ Heavy lift
Reachability: External
Exploitability: Difficult
CWE: CWE-494 — Download of Code Without Integrity Check
Validate the local binary against an independent release hash.
The script generates the published checksum from the unverified
--binaryinput. The installer then accepts that same checksum, so it detects transfer corruption but cannot detect a tampered build artifact. Require a SHA-256 value from trusted release metadata and compare it before staging the binary.Based on learnings: locally supplied artifacts require an independent cryptographic hash before use.
🤖 Prompt for AI Agents