diff --git a/MEDIA_CAPTURE.md b/MEDIA_CAPTURE.md index 88918dc..b46212e 100644 --- a/MEDIA_CAPTURE.md +++ b/MEDIA_CAPTURE.md @@ -1,3 +1,7 @@ +# October 2026 distribution UI + +`project-import-2026-10-20.png` and `project-deployments-2026-10-20.png` are unaltered captures of the merged distribution UI, built from the product release branch on 20 October 2026. They use a disposable local Docker instance and a synthetic Weekend planner source folder. The folder contained a package.json and no Compose file; folder browsing, import and opening Add deployment were exercised through the UI. No production workload was changed. These are interface demonstrations, not deployment-success evidence. The tour captions distinguish them from the dated production evidence below. + # Public evidence captures The public site uses unaltered desktop captures from the operator's authenticated GroundControl interface, captured on 22 September 2026. No generated interface or chat image is presented as product evidence. diff --git a/README.md b/README.md index b347af2..b5a3cbb 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ GroundControl itself is a self-hosted, single-tenant control plane. Each operato ## Current product story +“Put your agents to work” leads with GroundControl’s promise: deploy and operate applications with the agents you use, on infrastructure you own. The homepage brings the article’s operational context, MCP tools, OAuth access and durable execution into the product story. It explains what the connection enables: inspect application state, request supported deployments, and return to their recorded results. + +The homepage uses a dark theme with Serendepify’s lime and coral accents, with Schibsted Grotesk headings, Hanken Grotesk body text and JetBrains Mono details. Fonts are self-hosted through Next.js. + +The product tour and dated deployment evidence describe available capabilities. The separate Autopilot section is explicitly marked **Product direction**; customer-journey testing and proactive recovery are not presented as available features. The installation guide remains the primary call to action. + GroundControl gives software agents bounded infrastructure capabilities through MCP + OAuth: - inspect deployments, runtime and health; @@ -15,7 +21,7 @@ GroundControl gives software agents bounded infrastructure capabilities through - use connector capability health for GitHub, GHCR and Daytona; - keep SSH keys, provider credentials and the human PTY outside the agent tool surface. -Fresh installs use the canonical on-host installer and a one-time human ownership claim. +Fresh installs start with the computer launcher: local Docker or a remote Linux server, followed by a one-time ownership claim. The canonical on-host installer remains available for server operators. ## Verified deployment proof @@ -34,13 +40,14 @@ The full deployment and Daytona contract is maintained in the main repository at ## Install -Human-readable: +On your computer (macOS / Linux, or Windows through WSL): ```bash -curl -fsSL https://raw.githubusercontent.com/teckedd-code2save/groundcontrol/main/scripts/install | sudo bash +curl -fsSL https://raw.githubusercontent.com/teckedd-code2save/groundcontrol/main/scripts/start -o groundcontrol-start +bash groundcontrol-start ``` -Agent-oriented JSON result: +Directly on a Linux server, with an agent-oriented JSON result: ```bash curl -fsSL https://raw.githubusercontent.com/teckedd-code2save/groundcontrol/main/scripts/install \ @@ -78,8 +85,9 @@ MIT ## Native documentation and public evidence -The complete adoption path lives at `/docs`. Twelve guides cover the philosophy and workload model, install/claim, next steps after installation, HTTPS publishing, host discovery, existing application enrollment, new template deployments, ChatGPT OAuth/MCP, deployment automation, maintenance, troubleshooting and evidence. No GitHub visit is required to follow a guide. +The complete adoption path lives at `/docs`. Thirteen guides cover projects and deployment instances, the philosophy and workload model, install/claim, next steps after installation, HTTPS publishing, host discovery, existing application enrollment, new template deployments, ChatGPT OAuth/MCP, deployment automation, maintenance, troubleshooting and evidence. No GitHub visit is required to follow a guide. +- `content/setup-guides.tsx` contains local/remote setup and the project/source/deployment model. - `content/guides.tsx` contains the guide sections, runnable examples and expected results. - `content/journey-guides.tsx` contains the philosophy, post-install, discovery and new-deployment guides. `content/guide-parts.tsx` supplies shared guide elements. - `content/guide-index.ts` defines sidebar order and search terms. @@ -89,4 +97,8 @@ The complete adoption path lives at `/docs`. Twelve guides cover the philosophy - Product screenshots open at full size and preserve their aspect ratio. - See `MEDIA_CAPTURE.md` for capture provenance, dates and claim boundaries. -Validate guide links/anchors, assets, endpoint formatting, clipboard behavior, product-tour keyboard navigation and checklist state with `npm test`. Review the actual rendered pages and capture any limits in `SITE_REVIEW.md`. The current browser runtime does not expose viewport emulation, so real phone testing remains outstanding. +Validate guide links/anchors, assets, endpoint formatting, clipboard behavior, product-tour keyboard navigation and checklist state with `npm test`. Review the actual rendered pages and capture any limits in `SITE_REVIEW.md`. Browser viewport testing covers desktop and narrow layouts; physical phone testing remains outstanding. + +## Sharing + +Share https://trygroundcontrol.serendepify.com/ or link directly to `/docs/getting-started`. The root metadata provides a dark Open Graph image and a large social card, generated at build time by `app/opengraph-image.tsx`. The install guide is self-contained; the public site does not collect credentials or expose an operator login. diff --git a/SITE_REVIEW.md b/SITE_REVIEW.md index 890beae..a7ec021 100644 --- a/SITE_REVIEW.md +++ b/SITE_REVIEW.md @@ -1,6 +1,25 @@ -# Public site review, 22 September 2026 +# Distribution release site review · 20 October 2026 + +The homepage, article and all thirteen handbook guides now share a dark theme with lime calls to action. The copy leads with agentic deployment on infrastructure the visitor owns, and explains the new local/remote computer launcher, folder/GitHub project import, and connect-existing/launch-new deployment paths. The project model separates application source from runtime instances. Desktop limits, WSL, AMD64 emulation and the server-only HTTPS/upgrade flows are explicit in the relevant guides. + +The first two walkthrough stages use fresh captures of the distribution UI with a disposable example project. The September OAuth and production-operation evidence keeps its original dates and qualifications. No production deployment was used or changed for the new captures. A static dark Open Graph image and large social card make the public URL ready to share. + +Validation: lint, TypeScript, all nine behavior/navigation tests and the production build passed. Browser review covered the homepage at 1280 and 390 pixels, walkthrough switching, the 390-pixel installation guide and expandable documentation navigation, image loading and the generated 1200×630 share card. No horizontal page overflow was observed. Actual physical-device testing remains unverified. + +## Earlier reviews + +# Public site review + +## Serendepify brand alignment, 3 October 2026 + +The public marketing site adopts the company site's current visual language while leading with GroundControl’s own promise: “Put your agents to work.” The opening explains agentic deployment on infrastructure the reader owns. The capability section brings forward the article’s application context, scoped execution and durable results, and links directly to the full story. The navigation now calls that article “Why GroundControl.” The proof section explains signed GitHub deployment automation and the agent’s access to recorded outcomes. Warm paper, lime accents, an outlined headline and the company's font families connect the two sites without replacing GroundControl's identity or its real product screenshots. + +Available capabilities stay separate from the clearly labeled Autopilot product direction. The existing September evidence dates and provenance qualifications are preserved. Installation, native guides, product-tour behavior and operator-owned authentication boundaries are unchanged. No operator instance or deployment is part of this revision. + +Local lint, TypeScript, all nine tests and the static production build passed. Browser review covered the homepage at 1280 pixels, its tour selection, the installation link, and the installation guide's expandable documentation menu at 390 pixels. Font inspection confirmed Schibsted Grotesk headings and Hanken Grotesk body text. Neither the homepage nor the installation guide had horizontal document overflow at 390 pixels after constraining the installation panel's grid columns; long commands retain their own scroll area. Physical device testing remains outstanding. + +## Product journey revision, 22 September 2026 -## Product journey revision The homepage now has a four-part product tour using actual desktop captures, a post-install sequence, an illustrated workload model, inspectable deployment proof and direct learning paths. Twelve native guides cover the GroundControl philosophy, installation, next steps, publishing, discovery, enrollment, new template deployments, agent access, automation, maintenance, troubleshooting and evidence. diff --git a/app/articles/agentic-deployment-with-oauth-and-mcp/page.tsx b/app/articles/agentic-deployment-with-oauth-and-mcp/page.tsx index 838884c..26cca27 100644 --- a/app/articles/agentic-deployment-with-oauth-and-mcp/page.tsx +++ b/app/articles/agentic-deployment-with-oauth-and-mcp/page.tsx @@ -45,7 +45,7 @@ export default function ArticlePage() { Connect an agent From merge to deployment The agent’s view - Use it on your VPS + Use your own infrastructure
@@ -183,9 +183,9 @@ export default function ArticlePage() {

Put it to work on your infrastructure.

- Install GroundControl, claim your instance and review the host - scan. Choose one application, confirm its identity and connect - your agent. A health check gives you a first result you can + Start GroundControl from your computer, locally or on a Linux + server. Add a project from a folder or GitHub, connect or launch + its deployment, and authorize your agent. A health check gives you a first result you can compare with the product interface. From there, follow the deployment guide for the operations your workload supports.

diff --git a/app/components/NextSteps.tsx b/app/components/NextSteps.tsx index 62d9da1..1788f57 100644 --- a/app/components/NextSteps.tsx +++ b/app/components/NextSteps.tsx @@ -19,10 +19,10 @@ const paths = [ { id: "new", title: "I want to deploy a new app", - intro: "Use a template to validate, create and enroll a new deployment.", + intro: "Add your project, then choose the launch path supported by its host.", steps: [ - ["Choose a template for your application", "new-deployment#choose"], - ["Connect and verify the source", "new-deployment#source"], + ["Add your project from a folder or GitHub", "projects#sources"], + ["Choose a host and deployment environment", "projects#deployments"], ["Configure and review the proposed deployment", "new-deployment#review"], ["Deploy and check the public result", "new-deployment#verify"], ["Grant your agent access to that workload", "agent-access#consent"], diff --git a/app/components/ProductTour.tsx b/app/components/ProductTour.tsx index 8b05600..8075ee6 100644 --- a/app/components/ProductTour.tsx +++ b/app/components/ProductTour.tsx @@ -6,24 +6,26 @@ import Capture from "./Capture"; const stages = [ { - title: "Discover", - heading: "Start with what is already running.", - text: "GroundControl reads the active host, finds Compose folders and containers, and presents candidates you can inspect.", - fact: "Review the candidates and choose which to enroll.", - file: "discovery-desktop.jpg", - alt: "GroundControl discovered workloads with source paths and Enrol deployment buttons", - href: "/docs/discovery", - link: "How discovery works", + title: "Project", + heading: "Start with the application you’re building.", + text: "Pick a folder from your computer or import a GitHub repository. Your project brings the source, purpose and deployment instances together.", + fact: "Add source first. Choose its deployments separately.", + file: "project-import-2026-10-20.png", + alt: "GroundControl Add project chooser with folder and GitHub import options", + caption: "Current interface · isolated demo · 20 October 2026", + href: "/docs/projects#sources", + link: "Add your first project", }, { - title: "Enrol", - heading: "Choose what belongs in GroundControl.", - text: "Enrol one candidate, keep its files where they are, and optionally group it into a project. Confirm its source, runtime and public address.", - fact: "Enrollment preserves the workload’s existing location.", - file: "enrollment-desktop.jpg", - alt: "GroundControl enrollment dialog showing optional project grouping", - href: "/docs/first-deployment", - link: "Follow the enrollment guide", + title: "Deploy", + heading: "Give each environment its own instance.", + text: "Connect an application already running on your host, or launch a new instance. Each deployment has its own environment, configuration and release history.", + fact: "Local Docker or your Linux server. Your infrastructure.", + file: "project-deployments-2026-10-20.png", + alt: "GroundControl Add deployment dialog offering connect existing or launch new", + caption: "Current interface · example project · 20 October 2026", + href: "/docs/projects#deployments", + link: "Choose a deployment path", }, { title: "Connect", @@ -31,6 +33,7 @@ const stages = [ text: "Add your instance’s MCP endpoint to a compatible client, sign in through OAuth and select the deployments it may access.", fact: "The grant names the capabilities and workloads.", file: "agents-desktop.jpg", + caption: "Operator interface · captured 22 September 2026", alt: "GroundControl Agents workspace showing a real active ChatGPT grant", href: "/docs/agent-access", link: "Connect your agent", @@ -41,6 +44,7 @@ const stages = [ text: "Read runtime checks and the public endpoint result. A durable operation ID lets your agent return to the same work after a timeout.", fact: "RentAWeekend recorded release · 21 September 2026.", file: "verification-desktop.jpg", + caption: "Recorded release · captured 22 September 2026", alt: "GroundControl runtime image verification and public endpoint evidence", href: "/docs/evidence", link: "Inspect the recorded evidence", @@ -109,7 +113,7 @@ export default function ProductTour() {
diff --git a/app/components/SiteChrome.tsx b/app/components/SiteChrome.tsx index c782df5..36d30db 100644 --- a/app/components/SiteChrome.tsx +++ b/app/components/SiteChrome.tsx @@ -38,7 +38,7 @@ export function Header() { Approach Docs - Field notes + Why GroundControl @@ -55,8 +55,12 @@ export function Footer() { GroundControl

- Open-source operations for infrastructure you own. -
A Serendepify product. + Agentic deployment on infrastructure you own. +
Built by{" "} + + Serendepify + {" "} + in Accra, Ghana.

- Safe, smooth, observable, agentic. + Your infrastructure. Your final say. ); } diff --git a/app/components/WorkloadModel.tsx b/app/components/WorkloadModel.tsx index fc6a75b..2f57b79 100644 --- a/app/components/WorkloadModel.tsx +++ b/app/components/WorkloadModel.tsx @@ -5,16 +5,21 @@ export default function WorkloadModel() { aria-label="Example of GroundControl entities and their relationships" >
- Example · one application, one deployment, several services + Example · one application, independent deployments
Project Weekend planner - Optional organization + Folder / GitHub repository +
+
+ Development + weekend-local + Docker on your computer
- Deployment + Production weekend-production On your VPS
diff --git a/app/docs/[slug]/page.tsx b/app/docs/[slug]/page.tsx index 76f96cb..0b85d81 100644 --- a/app/docs/[slug]/page.tsx +++ b/app/docs/[slug]/page.tsx @@ -29,7 +29,7 @@ export default async function GuidePage({ if (!guide) notFound(); const index = guideIndex.findIndex((g) => g.slug === slug); const nextFor: Record = { - "after-install": "discovery", + "after-install": "projects", publishing: "discovery", "first-deployment": "agent-access", "new-deployment": "agent-access", @@ -99,7 +99,7 @@ export default async function GuidePage({

Updated
- 22 September 2026 + {guide.updated ?? "22 September 2026"}

diff --git a/app/docs/page.tsx b/app/docs/page.tsx index 1faaf5f..ec563d1 100644 --- a/app/docs/page.tsx +++ b/app/docs/page.tsx @@ -17,7 +17,7 @@ export default function DocsPage() {

The operator’s handbook

- From your first scan + From your first project
to a verified operation.

@@ -30,13 +30,13 @@ export default function DocsPage() { 01 / Start

I need to install it.

-

Install, claim and connect the local host.

+

Choose your computer or a server and open the setup link.

Installation guide → 02 / Continue

It’s installed. Now what?

-

Review discovery and choose your first application.

+

Add a project, then connect or launch a deployment.

Follow the next steps → diff --git a/app/globals.css b/app/globals.css index f323cb9..4ae1fd1 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,23 +1,37 @@ @import "tailwindcss"; :root { - --paper: #f7f6f2; - --surface: #ffffff; - --ink: #202923; - --muted: #626a64; - --line: #dcdfd8; - --dark: #141c18; - --dark-line: #38473e; - --green: #326349; - --soft-green: #eaf0e8; - --code: #e1eadd; - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); + /* Serendepify's lime and coral on a dark, warm-neutral canvas. */ + --paper: #11130f; + --paper-deep: #171b14; + --lime: #c8ff3d; + --coral: #ff8165; + --grid-line: rgba(225, 237, 203, 0.045); + --lime-wash: rgba(200, 255, 61, 0.08); + --light-ink: #f0f2e8; + --dark-muted: #b7bfab; + --dark-active: #252d1b; + --panel-line: #414a36; + --surface: #1c2118; + --ink: #f0f2e8; + --muted: #b7bfab; + --line: #353d2d; + --dark: #0b0e09; + --dark-line: #353d2d; + --green: #c8ff3d; + --soft-green: #232c18; + --code: #20271a; + --on-accent: #11160a; + --accent-hover: #daff84; + --font-sans: var(--font-brand-body); + --font-display: var(--font-brand-display); + --font-mono: var(--font-brand-mono); } * { box-sizing: border-box; } html { + color-scheme: dark; scroll-behavior: smooth; scroll-padding-top: 100px; } @@ -56,8 +70,8 @@ pre:focus-visible, outline-offset: 5px; } ::selection { - background: #d5e6d6; - color: var(--ink); + background: var(--lime); + color: var(--on-accent); } h1, h2, @@ -69,7 +83,8 @@ figure { h1, h2, h3 { - font-weight: 500; + font-family: var(--font-display), sans-serif; + font-weight: 600; } img { display: block; @@ -118,8 +133,8 @@ img { top: -100px; z-index: 99; padding: 14px 22px; - background: var(--ink); - color: white; + background: var(--lime); + color: var(--on-accent); } .skip-link:focus { top: 12px; @@ -139,16 +154,19 @@ img { gap: 30px; min-height: 48px; padding: 15px 21px; - background: var(--ink); - color: white; - border: 1px solid var(--ink); - border-radius: 4px; + background: var(--lime); + color: var(--on-accent); + border: 1px solid var(--lime); + border-radius: 8px; font-size: 14px; - font-weight: 500; + font-weight: 600; transition: background 0.2s; } .button:hover { - background: var(--green); + background: var(--accent-hover); +} +.button > span { + color: inherit; } .button.compact { min-height: 42px; @@ -173,7 +191,7 @@ img { align-items: center; } .site-header { - min-height: 82px; + min-height: 76px; padding: 0 max(32px, calc((100% - 1264px) / 2)); display: flex; justify-content: space-between; @@ -244,20 +262,22 @@ img { /* Product story */ .landing-hero { display: grid; - grid-template-columns: 1.15fr 1fr; + grid-template-columns: 1.12fr 1fr; gap: 8%; - padding-block: 78px 70px; + padding-block: 72px 60px; align-items: end; } .hero-heading h1 { - font-size: clamp(54px, 5.65vw, 79px); - line-height: 1.05; + font-size: clamp(72px, 7.6vw, 106px); + line-height: 0.96; + font-weight: 600; letter-spacing: -0.063em; margin-top: 25px; } .hero-heading em { font-style: normal; - color: var(--green); + color: transparent; + -webkit-text-stroke: 1.4px var(--ink); } .hero-intro { padding-bottom: 5px; @@ -312,7 +332,7 @@ img { border: 1px solid var(--dark-line); border-radius: 8px; background: var(--dark); - color: #edf1e8; + color: var(--light-ink); overflow: hidden; } .tour-tabs { @@ -327,7 +347,7 @@ img { align-items: center; gap: 17px; font-size: 15px; - color: #bec9be; + color: var(--dark-muted); border-bottom: 2px solid transparent; text-align: left; } @@ -337,7 +357,7 @@ img { .tour-tabs button > span:first-child { font-family: var(--font-mono); font-size: 10px; - color: #a0afa4; + color: var(--dark-muted); } .tour-tabs button > span:last-child { margin-left: auto; @@ -345,11 +365,11 @@ img { } .tour-tabs button[aria-selected="true"] { color: white; - background: #26372d; - border-bottom-color: #97bd9b; + background: var(--dark-active); + border-bottom-color: var(--lime); } .product-tour :focus-visible { - outline-color: #b5d2b5; + outline-color: var(--lime); outline-offset: -5px; } .tour-panel { @@ -361,7 +381,7 @@ img { min-height: 555px; } .tour-copy .eyebrow { - color: #a3b4a6; + color: var(--dark-muted); font-size: 10px; } .tour-copy h2 { @@ -374,7 +394,7 @@ img { font-size: 14px; line-height: 1.85; margin-top: 19px; - color: #bcc8bd; + color: var(--dark-muted); } .tour-copy .tour-fact { border-top: 1px solid var(--dark-line); @@ -386,7 +406,7 @@ img { display: inline-block; font-size: 13px; color: white; - border-bottom: 1px solid #64876a; + border-bottom: 1px solid var(--lime); padding: 12px 0 6px; margin-top: 12px; } @@ -487,8 +507,8 @@ img { color: var(--green); } .philosophy-band { - background: #e9eee7; - border-block: 1px solid #d4ded1; + background: var(--paper-deep); + border-block: 1px solid var(--line); padding-block: 75px; } .philosophy-grid { @@ -499,24 +519,24 @@ img { } .philosophy-grid > div > p:not(.eyebrow) { font-size: 15px; - color: #536151; + color: var(--muted); line-height: 1.85; margin-top: 22px; } .philosophy-grid .text-link { - border-color: #bdcbbc; + border-color: var(--panel-line); margin-top: 20px; } .workload-model { padding: 25px; - border: 1px solid #c7d4c5; + border: 1px solid var(--panel-line); border-radius: 5px; - background: #f7faf3; + background: var(--paper); } .workload-model figcaption { font-size: 11px; line-height: 1.6; - color: #52694f; + color: var(--muted); padding-bottom: 22px; } .model-row { @@ -524,14 +544,14 @@ img { flex-wrap: wrap; gap: 7px 18px; padding: 17px; - background: white; - border: 1px solid #d0dccb; + background: var(--surface); + border: 1px solid var(--panel-line); align-items: center; } .model-row > span { font-size: 10px; font-family: var(--font-mono); - color: #63715e; + color: var(--muted); width: 80px; } .model-row strong { @@ -541,11 +561,11 @@ img { .model-row small { width: 100%; padding-left: 98px; - color: #687362; + color: var(--muted); font-size: 10px; } .model-deployment { - border-left: 1px solid #b6c8b2; + border-left: 1px solid var(--panel-line); margin: 0 0 0 15px; padding: 20px 0 0 17px; } @@ -556,17 +576,17 @@ img { padding: 13px 0; } .model-services > span { - border: 1px solid #d0dccb; + border: 1px solid var(--panel-line); padding: 13px; font-family: var(--font-mono); font-size: 12px; - background: #eaf1e4; + background: var(--paper-deep); } .model-services small { display: block; font-family: var(--font-sans); font-size: 10px; - color: #586b52; + color: var(--muted); margin-top: 7px; } .model-route { @@ -574,7 +594,7 @@ img { } .workload-model > p { font-size: 12px; - color: #52654b; + color: var(--muted); line-height: 1.8; margin-top: 20px; } @@ -688,10 +708,13 @@ img { } .start-grid { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9%; align-items: center; } +.start-grid > div { + min-width: 0; +} .start-grid .eyebrow, .start-grid .small { color: #a5b5a7; @@ -793,7 +816,7 @@ img { width: 100%; min-height: 48px; padding: 13px; - border: 1px solid #b6c0b5; + border: 1px solid var(--panel-line); border-radius: 3px; color: var(--ink); font-family: var(--font-mono); @@ -805,7 +828,7 @@ img { margin-top: 13px !important; } .endpoint-builder .input-error { - color: #a03f2e !important; + color: var(--coral) !important; } .endpoint-builder .code-block { margin-bottom: 13px; @@ -852,7 +875,7 @@ img { } .docs-sidebar nav a:hover { color: var(--ink); - background: #ecefe7; + background: var(--surface); } .docs-sidebar nav a.active { border-left-color: var(--green); @@ -866,7 +889,7 @@ img { .nav-group > p { font-size: 10px; font-family: var(--font-mono); - color: #737a72; + color: var(--muted); padding: 7px 12px 8px; } .sidebar-note { @@ -971,7 +994,7 @@ img { .prose li { font-size: 16px; line-height: 1.8; - color: #4c584e; + color: var(--muted); } .prose p + p { margin-top: 19px; @@ -1004,9 +1027,9 @@ img { .prose code { font-family: var(--font-mono); font-size: 0.82em; - background: #eaf0e5; - color: #375534; - border: 1px solid #dbe4d6; + background: var(--soft-green); + color: var(--ink); + border: 1px solid var(--line); padding: 2px 4px; border-radius: 3px; overflow-wrap: anywhere; @@ -1024,8 +1047,8 @@ img { } .callout { padding: 19px 21px; - border-left: 2px solid #adbda5; - background: #eff1e9; + border-left: 2px solid var(--panel-line); + background: var(--paper-deep); margin-block: 26px; } .callout > strong { @@ -1065,11 +1088,11 @@ td { } th { font-weight: 600; - background: #eaf0e5; - color: #42553d; + background: var(--soft-green); + color: var(--ink); } td { - color: #4f5c4c; + color: var(--muted); } td + td, th + th { @@ -1094,7 +1117,7 @@ tr:last-child td { flex-direction: column; gap: 10px; padding: 19px; - background: white; + background: var(--surface); } .scope-map > div + div { border-left: 1px solid var(--line); @@ -1152,7 +1175,7 @@ tr:last-child td { gap: 0; margin-block: 15px 27px; border: 1px solid var(--line); - background: white; + background: var(--surface); border-radius: 5px; } .docs-entrypoints > a { @@ -1264,7 +1287,7 @@ tr:last-child td { } .next-steps { border: 1px solid var(--line); - background: white; + background: var(--surface); border-radius: 5px; margin-block: 26px; overflow: hidden; @@ -1353,7 +1376,7 @@ tr:last-child td { margin: 0; padding: 16px 20px; font-size: 11px; - background: #f4f6f0; + background: var(--paper-deep); color: var(--muted); line-height: 1.7; } @@ -1455,7 +1478,7 @@ tr:last-child td { .operation-record { padding: 25px; background: var(--soft-green); - border: 1px solid #cedbc8; + border: 1px solid var(--line); margin-block: 25px; } .operation-record > code { @@ -1472,7 +1495,7 @@ tr:last-child td { .operation-record dl > div { display: flex; gap: 22px; - border-top: 1px solid #cdd9c8; + border-top: 1px solid var(--line); padding: 13px 0; font-size: 13px; } @@ -1670,7 +1693,7 @@ tr:last-child td { gap: 35px; } .start-grid { - grid-template-columns: 1fr; + grid-template-columns: minmax(0, 1fr); gap: 35px; } .start-grid .code-block { @@ -1954,7 +1977,7 @@ tr:last-child td { padding: 0; border: 1px solid var(--line); border-radius: 4px; - background: white; + background: var(--surface); } .docs-toggle { display: flex; @@ -2166,6 +2189,204 @@ tr:last-child td { font-size: 12px; } } +/* Brand story sections use Serendepify's visual language with real product evidence. */ +.hero-field { + background: radial-gradient(ellipse at 60% 24%, var(--lime-wash), transparent 40%), + repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 88px); +} +.hero-heading .eyebrow { + text-transform: uppercase; + letter-spacing: .12em; + font-size: 10px; +} +.hero-heading .status-dot { + background: var(--coral); + box-shadow: 0 0 0 4px color-mix(in srgb, var(--coral) 12%, transparent); +} +.hero-intro .lead { + font-size: clamp(24px, 2.25vw, 32px); + line-height: 1.25; + font-family: var(--font-display), sans-serif; + font-weight: 500; +} +.hero-intro > p + p { + font-size: 17px; + line-height: 1.65; +} +.button.secondary { + background: transparent; + color: var(--ink); + border-color: var(--panel-line); +} +.button.secondary > span { + color: var(--ink); +} +.button.secondary:hover { + background: var(--surface); +} +.hero-intro .returning-link { + margin-top: 15px; + border: 0; + color: var(--muted); +} +.hero-intro .returning-link:hover { + color: var(--ink); + text-decoration: underline; +} +.hero-spec { + border-top: 1px solid var(--line); + padding-top: 20px; +} +.hero-field .tour-section { + padding-bottom: 64px; +} +.product-tour { + border-radius: 12px; + box-shadow: 0 24px 50px color-mix(in srgb, var(--ink) 10%, transparent); +} +.tour-tabs button[aria-selected="true"] > span:first-child { + color: var(--lime); +} +.capability-story { + padding-block: 80px 92px; +} +.capability-story .section-heading h2 { + max-width: 13ch; +} +.capability-columns { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-top: 1px solid var(--line); +} +.capability-columns article { + padding: 28px 30px 0 0; +} +.capability-columns article + article { + border-left: 1px solid var(--line); + padding-left: 30px; +} +.capability-columns .mono { + color: var(--green); +} +.capability-columns h3 { + font-size: 23px; + letter-spacing: -.045em; + line-height: 1.2; + margin-top: 25px; +} +.capability-columns p { + color: var(--muted); + font-size: 16px; + line-height: 1.7; + margin-top: 15px; +} +.direction-section { + display: grid; + grid-template-columns: .65fr 1.35fr; + gap: 60px; + padding-block: 44px 54px; + border-block: 1px solid var(--line); +} +.direction-label { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: 16px; +} +.direction-badge { + border: 1px solid var(--panel-line); + border-radius: 5px; + padding: 7px 10px; + font: 11px/1.4 var(--font-mono), monospace; + color: var(--green); +} +.direction-section h2 { + font-size: clamp(30px, 3vw, 42px); + line-height: 1.15; + letter-spacing: -.04em; +} +.direction-section p { + max-width: 640px; + color: var(--muted); + font-size: 16px; + line-height: 1.8; + margin-top: 20px; +} +.direction-section .text-link { + margin-top: 14px; +} +.company-link { + text-decoration: underline; + text-underline-offset: 3px; +} +.company-link:hover { + color: var(--ink); +} +.start-grid .button { + background: var(--lime); + color: var(--ink); + border-color: var(--lime); +} +.start-grid .button > span { + color: var(--ink); +} +.start-grid .button:hover { + background: var(--light-ink); + border-color: var(--light-ink); +} +@media (max-width: 950px) { + .direction-section { + grid-template-columns: 1fr; + gap: 28px; + } + .direction-label { + flex-direction: row; + align-items: center; + flex-wrap: wrap; + } +} +@media (max-width: 700px) { + .capability-story { + padding-block: 54px; + } + .capability-columns { + grid-template-columns: 1fr; + } + .capability-columns article { + padding: 24px 0; + } + .capability-columns article + article { + border-left: 0; + border-top: 1px solid var(--line); + padding-left: 0; + } + .capability-columns h3 { + margin-top: 12px; + } + .capability-columns p { + margin-top: 10px; + } + .hero-field .tour-section { + padding-bottom: 44px; + } + .direction-section { + padding-block: 32px; + gap: 24px; + } + .hero-intro .actions { + gap: 10px; + } + .hero-intro .actions .button { + flex: 1 1 180px; + } +} +@media (prefers-contrast: more), (forced-colors: active) { + .hero-heading em { + color: var(--ink); + -webkit-text-stroke: 0; + } +} + @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; diff --git a/app/layout.test.tsx b/app/layout.test.tsx index 60eb5df..e153951 100644 --- a/app/layout.test.tsx +++ b/app/layout.test.tsx @@ -1,8 +1,9 @@ import { beforeAll, describe, expect, it, vi } from "vitest"; vi.mock("next/font/google", () => ({ - Geist: () => ({ variable: "--font-geist-sans" }), - Geist_Mono: () => ({ variable: "--font-geist-mono" }), + Hanken_Grotesk: () => ({ variable: "--font-brand-body" }), + Schibsted_Grotesk: () => ({ variable: "--font-brand-display" }), + JetBrains_Mono: () => ({ variable: "--font-brand-mono" }), })); import { render, screen } from "@testing-library/react"; diff --git a/app/layout.tsx b/app/layout.tsx index 019ac32..1967bd0 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,21 +1,34 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Hanken_Grotesk, JetBrains_Mono, Schibsted_Grotesk } from "next/font/google"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", +const bodyFont = Hanken_Grotesk({ + variable: "--font-brand-body", subsets: ["latin"], }); -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const displayFont = Schibsted_Grotesk({ + variable: "--font-brand-display", + subsets: ["latin"], +}); + +const monoFont = JetBrains_Mono({ + variable: "--font-brand-mono", subsets: ["latin"], }); export const metadata: Metadata = { - title: "GroundControl | Open-source agentic deployment with MCP + OAuth", + metadataBase: new URL("https://trygroundcontrol.serendepify.com"), + openGraph: { + type: "website", + siteName: "GroundControl", + title: "Put your agents to work | GroundControl", + description: "Deploy and operate on infrastructure you own. Start on your computer or a Linux server, bring a project from a folder or GitHub, and connect your agent.", + }, + twitter: { card: "summary_large_image" }, + title: "GroundControl | Agentic deployment on infrastructure you own", description: - "Open-source agentic deployment for Docker Compose infrastructure, with scoped OAuth and MCP access for software agents.", + "Connect your agents to your applications through MCP and OAuth. Inspect workloads, run supported deployments, and verify results on infrastructure you own. Open source and self-hosted.", icons: { icon: "/favicon.svg", shortcut: "/favicon.svg", @@ -28,10 +41,11 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + Skip to content diff --git a/app/opengraph-image.tsx b/app/opengraph-image.tsx new file mode 100644 index 0000000..ee75aa5 --- /dev/null +++ b/app/opengraph-image.tsx @@ -0,0 +1,26 @@ +import { ImageResponse } from "next/og"; + +export const alt = "GroundControl — Put your agents to work. Deploy and operate on infrastructure you own."; +export const size = { width: 1200, height: 630 }; +export const contentType = "image/png"; + +export default function Image() { + return new ImageResponse( +
+
+
GroundControl
+
Open source · Self-hosted · MCP + OAuth
+
+
+
+
Put your agents
to work.
+
+
Deploy and operate on infrastructure you own.
+
+
+
Your computer or your server.
trygroundcontrol.serendepify.com
+
+
, + size, + ); +} diff --git a/app/page.test.tsx b/app/page.test.tsx index fdce8c2..bc472cd 100644 --- a/app/page.test.tsx +++ b/app/page.test.tsx @@ -112,7 +112,7 @@ describe("The self-contained adoption journey", () => { it("replaces phone captures with current desktop evidence and clear provenance", () => { render(); expect( - screen.getByAltText(/GroundControl discovered workloads/), + screen.getByAltText(/GroundControl Add project chooser/), ).toBeInTheDocument(); fireEvent.click(screen.getByRole("tab", { name: /Connect/ })); expect( @@ -136,13 +136,13 @@ describe("The self-contained adoption journey", () => { }); it("lets readers navigate the product walkthrough using the keyboard", () => { render(); - const first = screen.getByRole("tab", { name: /Discover/ }); + const first = screen.getByRole("tab", { name: /Project/ }); fireEvent.keyDown(first, { key: "ArrowRight" }); - const enroll = screen.getByRole("tab", { name: /Enrol/ }); + const enroll = screen.getByRole("tab", { name: /Deploy/ }); expect(enroll).toHaveAttribute("aria-selected", "true"); expect(enroll).toHaveFocus(); expect(screen.getByRole("tabpanel")).toHaveTextContent( - "Choose what belongs", + "Give each environment", ); fireEvent.keyDown(enroll, { key: "End" }); expect(screen.getByRole("tab", { name: /Verify/ })).toHaveFocus(); @@ -159,8 +159,8 @@ describe("The self-contained adoption journey", () => { fireEvent.click(screen.getByRole("button", { name: /deploy a new app/ })); expect(screen.getByText("0 / 5 checked")).toBeInTheDocument(); expect( - screen.getByRole("link", { name: /Guide: Choose a template/ }), - ).toHaveAttribute("href", "/docs/new-deployment#choose"); + screen.getByRole("link", { name: /Guide: Add your project/ }), + ).toHaveAttribute("href", "/docs/projects#sources"); fireEvent.click( screen.getByRole("button", { name: /apps already run here/ }), ); diff --git a/app/page.tsx b/app/page.tsx index 20a088e..e47aa3e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -8,60 +8,111 @@ export default function Home() { return ( <>
-
-
-
-

- - Open-source agentic deployment -

-

- Give your agents -
- the access to -
- follow through. -

-
-
-

- Discover your applications, choose what to manage, and let your - agents help operate them. -

-

- GroundControl is a self-hosted control plane for your VPS. It - gives agents controlled access through OAuth and MCP, so approved - work can move from a request to a verified result without repeated - access and credential handoffs. -

-
- - Install GroundControl - - - Already installed? Start here → +
+
+
+
+

+ + Open-source agentic deployment +

+

+ Put your +
+ agents +
+ to work. +

+
+
+

+ Deploy and operate on infrastructure you own. +

+

+ Connect ChatGPT or a compatible MCP agent to your applications. + Give it the context and tools to deploy changes, inspect + workloads, and verify the result. You choose its + access. Your infrastructure stays yours. +

+
+ + Install GroundControl + + + See agents in action + +
+ + Already installed? Continue setup → +
+ Self-hosted + MCP + OAuth + Open source +
-
- Docker Compose - Your VPS - MCP + OAuth +
+
+
+

Connect your workloads. Put your agent to work.

+ The product today · actual interface
-
-
-
-
-

- A working connection to your infrastructure + +

+
+
+
+
+

01 / From instruction to execution

+

Give agents the context to act.

+
+

+ GroundControl connects your application’s source, containers, + configuration, and public address. Your agent works from that + shared context, with tools to carry an authorized request through + to a result you can inspect.

- Explore the product
- +
+ {[ + [ + "01", + "Inspect real application state.", + "Ask your agent what is deployed, read the logs, and check service health. It works from your application’s state and deployment history.", + ], + [ + "02", + "Let your agent take action.", + "Approve the capabilities and deployments it can use through OAuth. GroundControl executes supported deployment requests on your infrastructure while holding the credentials.", + ], + [ + "03", + "Follow through to the result.", + "Get runtime checks and public endpoint evidence for the operation. A durable operation ID lets your agent return to the same work after a timeout or in a later conversation.", + ], + ].map(([number, title, text]) => ( +
+ {number} +

{title}

+

{text}

+
+ ))} +
+ + Why GroundControl +

Your infrastructure, connected to the agents you use.

+ + Read the story + +
-

Installation is the beginning

+

02 / Start with what you have

You installed it.
@@ -69,30 +120,30 @@ export default function Home() {

- The local host is connected. GroundControl can now help you - understand what is running and bring one application into its - control plane. + Start on your computer or connect an existing Linux server. + Add the application you’re building, then decide where and how + its deployments run.

{[ [ "01", - "Review what was found", - "Confirm the server, Compose folders, containers and proxy. Correct scan paths when something is missing.", - "discovery", + "Choose your starting point", + "Run the launcher on your computer. Choose local Docker or a remote Linux server and open your private setup link.", + "getting-started", ], [ "02", - "Choose your workload", - "Enrol an existing application in place, or use Templates to create and enroll a new deployment.", - "after-install#choose-path", + "Add your project", + "Pick a folder or a GitHub repository. Keep the source, context and deployments for your application together.", + "projects", ], [ "03", - "Establish its identity", - "Check the source, runtime, configuration and public address. Understand tracking and management mode.", - "first-deployment#management-mode", + "Connect or launch a deployment", + "Connect an app that already runs, or launch a new instance. Give each deployment its own environment and host.", + "projects#deployments", ], [ "04", @@ -116,21 +167,24 @@ export default function Home() {
-

The GroundControl approach

+

03 / Autonomy without surrender

- Your application is + Your infrastructure.
- more than a container. + Your agents. +
+ Your final say.

- GroundControl connects the source, runtime and public route to - one workload identity. Your team and your agents can work from - that shared context. + Bring a project from your computer or GitHub. Connect its + existing deployments or launch a new instance on your own + infrastructure. Keep your sources and environments together.

- You choose the scope. The control plane holds the infrastructure - credentials and records execution. Verification shows what - worked and what still needs attention. + MCP gives your agent the tools. OAuth defines its access. You + can work through the interface or your agent, using the same + application identity and recorded results. Review and revoke + access from the Agents workspace.

Read the philosophy and core concepts → @@ -142,17 +196,18 @@ export default function Home() {
-

Used on a real VPS

+

04 / Evidence from a real VPS

- The work leaves + From GitHub push
- something you can inspect. + to agent insight.

- GroundControl deployed RentAWeekend from a GitHub push. ChatGPT - connected through MCP to inspect its health and read the operation - record. + For managed workloads with merge automation enabled, a signed + GitHub push starts a deployment your agent can follow. In this + recorded example, GroundControl deployed RentAWeekend, and ChatGPT + inspected its health and operation record through MCP.

@@ -185,18 +240,19 @@ export default function Home() { Inspect the deployment record →
- - Engineering field notes -

- GroundControl: open-source agentic deployment with OAuth and MCP. -

- - Read the article - - +
+
+
Where we’re goingProduct direction
+
+

From verified operations
to proactive recovery.

+

+ Serendepify’s vision is a system that understands service relationships, + tests affected customer journeys, and helps recover from regressions + within an operator’s policy. This is the direction for Autopilot, + not a promise of unattended recovery in today’s release. +

+ Explore the Serendepify vision +
@@ -222,9 +278,9 @@ export default function Home() { "philosophy", ], [ - "Discovery & enrollment", - "Where the scanner looks and what enrollment changes.", - "discovery", + "Projects & deployments", + "Folder and GitHub imports, environments and running instances.", + "projects", ], [ "Connect your agent", @@ -252,13 +308,14 @@ export default function Home() {

Start with one host and one application

- Make your infrastructure + Your infrastructure.
- accessible to your agent. + Ready for your agent.

- Install privately, claim ownership, and choose the first - workload. + Install GroundControl, choose an application, and connect your + agent. Start with a health check, then explore the operations + your workload supports.

Follow the installation guide @@ -266,13 +323,13 @@ export default function Home() {

- Linux · Docker · root or sudo + Choose this computer or a remote Linux server.
- Read the installation guide for prerequisites and host access. + macOS / Linux · Windows through WSL · Docker for local installs.

diff --git a/content/guide-index.ts b/content/guide-index.ts index 49e2d9a..52557ec 100644 --- a/content/guide-index.ts +++ b/content/guide-index.ts @@ -13,11 +13,11 @@ export const guideIndex = [ { slug: "getting-started", title: "Install & claim", - short: "Start on your VPS", + short: "Start on your computer", group: "Set up", description: - "Installation commands, SSH tunnel, ownership and host checks.", - keywords: "linux VPS docker bootstrap install claim setup", + "Choose local Docker or a remote Linux server and open your private setup link.", + keywords: "linux macOS Windows WSL desktop VPS docker bootstrap install claim setup", }, { slug: "after-install", @@ -28,6 +28,14 @@ export const guideIndex = [ "Review the host scan and follow a checklist for your first application.", keywords: "next onboarding first steps dashboard workflow", }, + { + slug: "projects", + title: "Projects & deployments", + short: "Bring your application together", + group: "Set up", + description: "Pick a folder or GitHub repository, then connect or launch deployment instances.", + keywords: "project folder picker GitHub source import environment deployment local desktop", + }, { slug: "publishing", title: "Publish over HTTPS", @@ -58,7 +66,7 @@ export const guideIndex = [ { slug: "new-deployment", title: "Deploy a new app", - short: "Create with Templates", + short: "Launch a new instance", group: "Set up", description: "Choose a template, verify source, review configuration and deploy.", diff --git a/content/guides.tsx b/content/guides.tsx index f89eeac..f8f62b7 100644 --- a/content/guides.tsx +++ b/content/guides.tsx @@ -1,11 +1,13 @@ import type { ReactNode } from "react"; import { Check, Note, Table } from "./guide-parts"; +import { setupGuides } from "./setup-guides"; import { journeyGuides } from "./journey-guides"; import Link from "next/link"; import CodeBlock from "@/app/components/CodeBlock"; import Capture from "@/app/components/Capture"; import EndpointBuilder from "@/app/docs/_components/EndpointBuilder"; export type Guide = { + updated?: string; title: string; description: string; outcome: string; @@ -15,176 +17,9 @@ const install = "https://raw.githubusercontent.com/teckedd-code2save/groundcontrol/main/scripts/install"; export const guides: Record = { ...journeyGuides, - "getting-started": { - title: "Install GroundControl and claim your instance", - description: - "Start on a Linux VPS, reach the private installer through an SSH tunnel, and create your administrator account.", - outcome: - "A claimed, healthy GroundControl instance with its local server enrolled.", - sections: [ - { - id: "before-you-start", - title: "What you need", - body: ( - <> - -

- GroundControl is a privileged host operations tool. Its canonical - Compose file mounts the Docker socket and host directories such as{" "} - /opt, /etc and /var/www. - Install it on a host you intend it to manage. The MCP grant later - exposes a much narrower set of operations to an agent. -

- - ), - }, - { - id: "install", - title: "1. Run the installer on the VPS", - body: ( - <> -

- SSH into your VPS, then run this there. The script downloads the - published image, writes installation files under{" "} - /opt/groundcontrol, creates persistent database - storage and starts the container on 127.0.0.1:3003. -

- -

For an agent or script that needs structured output, use:

- - -

- Look for claim_required, healthy container checks, - a claimUrl and its expiry. The claim is single-use - and lasts 30 minutes by default. Keep its token private. -

-
- - ), - }, - { - id: "tunnel", - title: "2. Open the private instance from your computer", - body: ( - <> -

- In a second terminal on your own computer, open a tunnel. Replace{" "} - YOUR_USER and YOUR_VPS_IP with the SSH - account and address you normally use. -

- -

- Leave that terminal running. Open the installer’s full{" "} - http://127.0.0.1:3003/claim#token=… URL in your - computer’s browser. The URL reaches the VPS through your tunnel; - it is not a public management endpoint. -

- -

- If local port 3003 is occupied, use{" "} - - ssh -N -L 13003:127.0.0.1:3003 YOUR_USER@YOUR_VPS_IP - {" "} - and change only the port in the claim URL to 13003. -

-
- - ), - }, - { - id: "claim", - title: "3. Create the owner account", - body: ( - <> -

- On Claim GroundControl, enter an administrator - username, a password and its confirmation. The password requires - at least 12 characters with upper and lower case letters, a number - and a symbol. The installing agent should not retain it. -

-

- The claim code is read from the URL fragment. Submit the form to - establish ownership. If the claim expired before you used it, - rerun the installer on that still-unclaimed instance for a new - claim; an already-claimed instance uses its existing login. -

- -

- Onboarding opens after claim. The local host should already be - enrolled. You do not need to paste its SSH private key back into - GroundControl. Additional remote servers can be added separately - through Add server. -

-
- - ), - }, - { - id: "verify", - title: "4. Verify the installation", - body: ( - <> -

- Run these read-only checks on the VPS. Replace the port if you - changed it during installation. -

- -
-

- Continue with{" "} - After installation to - review the host scan and choose your first application. Remote - agents need{" "} - a reachable HTTPS address;{" "} - for a private evaluation, keep using the tunnel. -

- - ), - }, - ], - }, + ...setupGuides, publishing: { + updated: "20 October 2026", title: "Give your instance a stable HTTPS address", description: "Publish the control plane from onboarding, then verify the address your agent client will use for MCP and OAuth.", @@ -198,7 +33,7 @@ export const guides: Record = { <>

After claim, continue to the onboarding step titled{" "} - Publish this GroundControl instance. Choose a + Publish this GroundControl instance on a Linux server installation. Desktop installations remain local; this publishing flow is for servers. Choose a method appropriate for the host and DNS you control.

= { ], }, "first-deployment": { + updated: "20 October 2026", title: "Enrol an existing application", description: "Start with an existing Docker Compose application. Give GroundControl an explicit workload identity before granting an agent access.", @@ -388,28 +224,12 @@ export const guides: Record = { }, { id: "project", - title: "2. Group it into a project, if useful", + title: "2. Connect it to your application’s project", body: ( <> -

- Enrol deployment adds the candidate without a - project group. To group it immediately, open its options menu and - choose Enrol into project or{" "} - Create project and enrol. Selecting a project - completes that enrollment; there is no separate final submit - button in the selection dialog. -

- -

- You can change this later with the enrolled workload’s{" "} - Move to project action. Several environments or - applications can share a group while retaining distinct deployment - identities. -

+

From a project, choose Add deployment → Connect existing, select the workload and confirm its name and environment. The project holds your application’s source and its deployment instances.

+

You can also enrol from discovery, then use Move to project to organize it later. Moving or registering a deployment does not relocate files or restart its runtime.

+

See Projects & deployments to add sources from the folder picker or GitHub and connect additional environments.

), }, @@ -1059,6 +879,7 @@ export const guides: Record = { ], }, distribution: { + updated: "20 October 2026", title: "Upgrade, recover and uninstall", description: "Use the same installer for maintenance, with an explicit preview and a database/configuration backup before upgrade.", @@ -1070,6 +891,7 @@ export const guides: Record = { title: "1. Preview the target version", body: ( <> +

This maintenance flow is for the canonical Linux server installation. Rerunning the computer launcher reconnects; it does not upgrade an existing desktop instance. Keep the desktop configuration folder and database volume together.

Run this on the VPS that already hosts GroundControl. Replace{" "} YOUR_TAG with the published version or image tag you diff --git a/content/journey-guides.tsx b/content/journey-guides.tsx index 5025de6..2eda59c 100644 --- a/content/journey-guides.tsx +++ b/content/journey-guides.tsx @@ -8,6 +8,7 @@ import CodeBlock from "@/app/components/CodeBlock"; export const journeyGuides: Record = { philosophy: { + updated: "20 October 2026", title: "The GroundControl approach", description: "Understand the product, the things it manages, and how an agent gets a useful but bounded role in operating them.", @@ -34,8 +35,8 @@ export const journeyGuides: Record = { confirmations and expired grants still need attention.

- The starting point is a founder or small team running applications - with Docker Compose on a VPS. GroundControl also has human + Start on your computer with Docker, or on a Linux server with + the applications you already operate. GroundControl also has human controls for runtime, logs, environment, proxy configuration and terminal access. You can begin using those before connecting an external agent. @@ -58,11 +59,11 @@ export const journeyGuides: Record = { ], [ "Project", - "An optional group of related deployments. Moving a deployment between project groups changes organization, not its files or runtime.", + "Your application or product, with folder or GitHub sources and deployment instances. Organizing deployments preserves their files and runtime.", ], [ "Deployment", - "The enrolled application identity: host, source or container, Compose identity, repository, public URL and recorded releases where available.", + "An instance of an application on a particular host and environment, with a Compose or container runtime identity, public URL and recorded releases where available.", ], [ "Service / container", @@ -224,6 +225,7 @@ export const journeyGuides: Record = { ], }, "after-install": { + updated: "20 October 2026", title: "GroundControl is installed. What next?", description: "Go from a claimed instance to one understood workload and a verified agent connection.", @@ -236,15 +238,15 @@ export const journeyGuides: Record = { body: ( <>

- The canonical installer starts GroundControl privately, creates - persistent storage and connects the VPS it is running on as a - local host. Claim establishes your administrator account. You do + The launcher starts GroundControl privately, creates persistent + storage and connects the local Docker workspace or destination + Linux server. Claim establishes your administrator account. You do not need to add that same host again using SSH.

- After claim, onboarding asks how to publish the control plane. - Choose a stable HTTPS origin for remote MCP clients, or keep it - private while evaluating. On completion, GroundControl probes the + After claim, desktop onboarding verifies private local access. + On a Linux server, you can publish a stable HTTPS origin for + remote MCP clients or keep it private while evaluating. On completion, GroundControl probes the host and shows its findings.

= { <>

- For existing software, start in Deployments. For - a new workload, start in Templates. A template - deployment creates runtime resources and registers the result; - discovery and enrollment describe software already present. + Start in Projects → Add project and pick a folder + or GitHub repository. In that project, choose Add deployment + to connect an existing workload or launch a new instance. The + projects guide explains each path.

), @@ -333,7 +335,7 @@ export const journeyGuides: Record = { ], [ "Projects", - "Organize related deployments. Grouping does not relocate application files.", + "Add an application from a folder or GitHub and organize its deployment instances by host and environment.", ], [ "Runtime", @@ -401,7 +403,8 @@ export const journeyGuides: Record = { ], }, discovery: { - title: "Discover what is running on your VPS", + updated: "20 October 2026", + title: "Discover workloads on your host", description: "Understand where GroundControl looks, what a discovered candidate means, and how to resolve missing or unexpected results.", outcome: @@ -486,9 +489,11 @@ export const journeyGuides: Record = { ]} />

- Only enroll candidates you intend to track. A host can contain - temporary helper containers, old releases and infrastructure - services as well as customer applications. + Only enroll candidates you intend to track. Compose services from + the same stack are grouped together. Use Dismiss to hide a + suggestion, then Undo or Restore hidden to bring it back. This + does not stop or delete the workload. GroundControl excludes + its own helper containers.

), @@ -600,12 +605,22 @@ export const journeyGuides: Record = { ], }, "new-deployment": { + updated: "20 October 2026", title: "Deploy a new application from a template", description: "Use GroundControl’s Choose, Source, Config, Review and Deploy workflow to create and enroll a workload.", outcome: "A new deployment with its runtime, source identity and public verification result recorded in GroundControl.", sections: [ + { + id: "host", + title: "Start with your project and host", + body: <> +

Open your project and choose Add deployment → Launch new. Select the host and environment for this instance.

+

On local Docker, the current flow launches a single container image using its default command without custom environment variables. It does not build arbitrary folder or repository source. On a Linux server, continue through the Templates steps below.

+

If you have not added your application yet, pick a folder or GitHub repository first.

+ , + }, { id: "choose", title: "1. Choose the deployment shape", diff --git a/content/setup-guides.tsx b/content/setup-guides.tsx new file mode 100644 index 0000000..2ede14c --- /dev/null +++ b/content/setup-guides.tsx @@ -0,0 +1,106 @@ +import Link from "next/link"; +import type { Guide } from "./guides"; +import { Check, Note, Table } from "./guide-parts"; +import Capture from "@/app/components/Capture"; +import CodeBlock from "@/app/components/CodeBlock"; + +export const setupGuides: Record = { + "getting-started": { + updated: "20 October 2026", + title: "Start GroundControl from your computer", + description: "Choose this computer or an existing Linux server. The launcher prepares the instance and prints a private link for setup or login.", + outcome: "A private GroundControl workspace, your owner account and a clear next step for your first project.", + sections: [ + { id: "before-you-start", title: "Choose where it runs", body: <> +
+

Local GroundControl manages Docker workloads. It does not manage native Mac or Windows services. On a server, GroundControl is a privileged host operations tool; install it on infrastructure you intend it to manage.

+ }, + { id: "install", title: "1. Run the launcher on your computer", body: <> + +

Choose this computer or a remote server when prompted. Local setup uses Docker. Remote setup connects through SSH, installs GroundControl on the server and opens the private tunnel for you.

+

You can also choose the destination directly:

+ + +

The launcher prints a link on 127.0.0.1. A new instance opens setup; an instance you already own opens login. Local setup writes its configuration to .groundcontrol-desktop in the current folder by default. Retain that folder and the Docker database volume.

+ }, + { id: "tunnel", title: "2. Open your private setup link", body: <> +

Open the complete link printed by the launcher in your browser on the same computer. Its one-time claim token establishes ownership; keep the link private.

+
+

The remote server stays private unless you deliberately publish it. Rerunning the launcher reconnects to an existing installation; it does not upgrade it.

+ }, + { id: "claim", title: "3. Create your owner account", body: <> +

On Claim GroundControl, enter an administrator username and a password with at least 12 characters, upper and lower case letters, a number and a symbol. This account belongs to your own instance.

+

A claim link is single-use and expires after 30 minutes by default. Rerun the launcher for a fresh link if the unclaimed instance’s link expires. An already-claimed instance uses your existing login.

+

The local Docker workspace or destination Linux host is connected automatically. Continue setup to review it; you do not need to add that same host a second time.

+ }, + { id: "verify", title: "4. Verify and add your first project", body: <> +

Use the private verification step, then review the onboarding summary. On a desktop, the Linux environment belongs to the container; it is not the operating system of your Mac or Windows PC.

+

Open Projects → Add project. Pick a folder or a GitHub repository, then connect an existing deployment or launch a new one. Follow the projects and deployments guide.

+

A local-only address is for you on this computer. Remote MCP clients need a reachable HTTPS endpoint. The server installation supports publishing over HTTPS; desktop onboarding stays private.

+ }, + { id: "on-host", title: "Advanced: install directly on a Linux server", body: <> +

If you are already working in the destination server’s shell, use the canonical installer. Unlike the computer launcher, this command does not open an SSH tunnel on your computer.

+ +

Add -s -- --json after bash for structured installer output. From your computer, forward the default management port with:

+ +

Open the server installer’s complete claim link through that tunnel. Server installations live under /opt/groundcontrol by default and use persistent Docker database storage. See upgrade and recovery for maintenance.

+ }, + ], + }, + projects: { + updated: "20 October 2026", + title: "Your project, from source to deployments", + description: "Bring a folder or GitHub repository into GroundControl, then connect the instances of that application running on your infrastructure.", + outcome: "One project with its source and explicitly selected deployment instances, each with its own host and environment.", + sections: [ + { id: "model", title: "A project is the application you are building", body: <> +

A project gives your application or product a home. Its source can be a local folder or a GitHub repository. Its deployments are instances of that application—for example, development on your computer and production on a Linux server.

+
+

A project does not require a Compose file. Compose is one runtime method, alongside a standalone container. Registering source does not automatically build or start an application.

+ }, + { id: "sources", title: "1. Pick a folder or GitHub repository", body: <> + +
    +
  1. Open Projects → Add project.
  2. +
  3. Choose Folder to browse the host’s available locations and select your project folder. You do not need to type a path. For a local desktop install, use the Home, Workspace or Drives locations offered by the picker.
  4. +
  5. Or choose GitHub, select a repository and confirm the project details. Public repositories can be found by owner; private repositories require a GitHub connection with access. GroundControl retains the repository’s default branch.
  6. +
  7. Review the name and source, then add the project.
  8. +
+

Adding source records the project’s identity. It does not move your files or restart existing deployments. Removing a source link does not delete the original folder or repository.

+

The picker browses the selected host. A remote server’s filesystem is different from your computer’s. If Docker Desktop cannot read a local folder, allow that location in Docker Desktop’s file-sharing settings and select a smaller accessible folder. Windows users browse locations available to WSL and Docker.

+ }, + { id: "deployments", title: "2. Connect an existing app or launch an instance", body: <> + +

Open the project and select Add deployment. Choose the host, give the instance a useful name and set its environment.

+
+

Multiple instances may share source while running in different environments. A source folder alone is not a deployment and is not offered as a running workload to agents.

+

Follow existing app enrollment or new deployment setup for the remaining runtime-specific steps.

+ }, + { id: "discovery", title: "3. Keep discovery useful", body: <> +

Discovery suggests workloads on the selected host. Compose services from the same stack appear together, and GroundControl excludes its own helper containers.

+

Use Dismiss to hide a suggestion you do not want. Undo or Restore hidden brings it back. Dismissing a suggestion does not stop or remove the underlying workload.

+

Projects without Compose can still be added through the folder or GitHub flow. Their runtime becomes a deployment only when you explicitly connect or launch an instance.

+ }, + { id: "operate", title: "4. Work from a known deployment", body: <> +

Confirm the instance’s host, environment, services and public URL before operating it. Existing deployments, their configuration and their recorded history remain available when you organize them into projects.

+

For an external agent, authorize OAuth access to the specific deployments and capabilities it needs. Adding a project or connecting a runtime does not grant external-agent access on its own.

+ }, + ], + }, +}; diff --git a/public/proof/project-deployments-2026-10-20.png b/public/proof/project-deployments-2026-10-20.png new file mode 100644 index 0000000..5b95702 Binary files /dev/null and b/public/proof/project-deployments-2026-10-20.png differ diff --git a/public/proof/project-import-2026-10-20.png b/public/proof/project-import-2026-10-20.png new file mode 100644 index 0000000..bf8784a Binary files /dev/null and b/public/proof/project-import-2026-10-20.png differ