From 46a5e806446eae0081e7e8b3ba5193f649e652b7 Mon Sep 17 00:00:00 2001 From: Charles Green Date: Sat, 24 Oct 2026 22:01:37 +0900 Subject: [PATCH] Add Sync to the site and collapse products into a hub. Sync is a third sibling product, so the top nav is now Products, Docs, Blog, GitHub. /sync/ explains the coordination plane and sync-mcp, with a mermaid diagram of the HTTP and stdio path. --- CLAUDE.md | 3 +- README.md | 1 + config/_default/menus.en.toml | 15 ++-- content/products.md | 8 +++ content/sync.md | 58 +++++++++++++++ data/aixgate.yaml | 6 ++ data/products.yaml | 14 +++- data/sync.yaml | 71 +++++++++++++++++++ layouts/404.html | 1 + .../_markup/render-codeblock-mermaid.html | 10 +++ layouts/_default/baseof.html | 22 ++++++ layouts/_default/product.html | 16 ++--- layouts/_default/products.html | 45 ++++++++++++ layouts/index.html | 4 +- layouts/index.llms.txt | 2 +- layouts/partials/footer.html | 1 + layouts/partials/header.html | 3 + static/css/custom.css | 10 +++ 18 files changed, 265 insertions(+), 25 deletions(-) create mode 100644 content/products.md create mode 100644 content/sync.md create mode 100644 data/sync.yaml create mode 100644 layouts/_default/_markup/render-codeblock-mermaid.html create mode 100644 layouts/_default/products.html diff --git a/CLAUDE.md b/CLAUDE.md index d2711f7..b0dd5d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -152,7 +152,7 @@ Nothing to do. `release-sync.yml` updates `data/release.json` when aixgo publish ### Update site nav -Edit `config/_default/menus.en.toml`. Keep the top nav to ≤4 items (per recent design decision in commit `b8454a1`). +Edit `config/_default/menus.en.toml`. Keep the top nav to ≤4 items (per recent design decision in commit `b8454a1`). Sibling products (Code, Aixgate, Sync) live under `/products/`, not as extra top-nav entries. ## Quick Reference @@ -198,6 +198,7 @@ For Cloudflare Pages deploys, env vars are set in the Pages project settings (no - Live site: - Framework repo: - Sandbox companion: +- Coordination plane: - Hugo docs: - Cloudflare Pages docs: diff --git a/README.md b/README.md index a97ec1d..41d9a75 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ For framework documentation (API reference, ADRs), contribute to the [aixgo](htt - [aixgo](https://github.com/aixgo-dev/aixgo) — The Go framework this site documents. - [aixgate](https://github.com/aixgo-dev/aixgate) — The runtime sandbox companion. +- [sync](https://github.com/aixgo-dev/sync) — The coordination plane. MCP companion: [sync-mcp](https://github.com/aixgo-dev/sync-mcp). ## License diff --git a/config/_default/menus.en.toml b/config/_default/menus.en.toml index 17c3851..44f0c9b 100644 --- a/config/_default/menus.en.toml +++ b/config/_default/menus.en.toml @@ -1,23 +1,18 @@ # -- Main Menu -- # -# Two products sit above Docs because they are products, not reference. When a -# THIRD product lands, stop adding entries here: build /products/ as a hub page -# and collapse these two into one item. That is the trigger condition. +# Code and Aixgate used to sit above Docs. A third sibling (Sync) is the +# trigger to collapse them into one Products hub. Individual product URLs +# stay: /code/, /aixgate/, /sync/. # # "Code", not "Aixgo Code" — decided 2026-08-10: with the Aixgo wordmark on # every page, the short label reads fine, and the product page and footer # note carry the disambiguation. [[main]] - name = "Code" - url = "/code/" + name = "Products" + url = "/products/" weight = 5 -[[main]] - name = "Aixgate" - url = "/aixgate/" - weight = 6 - # /docs is an alias declared on content/guides/_index.md. Following it costs a # 308 to /docs/ and then a meta-refresh to /guides/. Point the nav at the # destination; the alias stays for inbound links. diff --git a/content/products.md b/content/products.md new file mode 100644 index 0000000..2a19156 --- /dev/null +++ b/content/products.md @@ -0,0 +1,8 @@ +--- +title: "The Aixgo products" +description: "A Go framework to build agents, and three products for what they do next." +layout: "products" +--- + + diff --git a/content/sync.md b/content/sync.md new file mode 100644 index 0000000..8b33b93 --- /dev/null +++ b/content/sync.md @@ -0,0 +1,58 @@ +--- +title: "Sync" +layout: "product" +data: "sync" +description: "Agents and workers share sessions, messages and jobs over one HTTP API. You run the binary. MCP clients use sync-mcp." +keywords: ['aixgo sync', 'agent coordination', 'mcp server', 'multi-tenant agent state', 's3 cas'] +--- + +## How it is used + +You run one Sync process per environment. Agents and other HTTP clients in an org and project share session documents, append and list thread messages, and create or claim jobs. Auth is a project-scoped bearer key. `/healthz` is the only open route. + +The default store is in memory and is lost on restart. Set `SYNC_S3_BUCKET` (and the related S3 or R2 variables) when the process should keep objects in object storage. + +Sync does not run agents, merge pull requests, or execute jobs. Workers that claim a job are what run the payload. + +## MCP companion + +MCP clients should not call that HTTP API themselves. [sync-mcp](https://github.com/aixgo-dev/sync-mcp) is a stdio MCP server that wraps Sync and exposes sessions, messages and jobs as tools. + +Treat listed messages, labels and job fields as untrusted data. `sync_job_create` can cause a worker to run `command` or `code_offload` work. Use `--read-only` unless the agent must write, and ask a human before create or claim. + +```mermaid +flowchart LR + MCPClient[MCP client] + HTTPClient[HTTP client] + MCP[sync-mcp] + Sync[aixgo-sync] + Store[(memory or S3/R2)] + MCPClient -->|stdio| MCP + MCP -->|HTTP + API key| Sync + HTTPClient -->|HTTP + API key| Sync + Sync --> Store +``` + +HTTP clients can call Sync directly. sync-mcp is optional. + +## Run + +```bash +# terminal 1 +export SYNC_API_KEYS="myorg:myproject:change-me" +aixgo-sync serve + +# terminal 2 (optional MCP front end, stdio) +SYNC_BASE_URL=http://localhost:8080 \ +SYNC_API_KEY=change-me \ +SYNC_ORG=myorg \ +SYNC_PROJECT=myproject \ +sync-mcp +``` + +Listen port is `SYNC_PORT` or `PORT` (default `8080`). The server will not start without `SYNC_API_KEYS` unless you set `SYNC_INSECURE_NO_AUTH=1` for local throwaway use. + +## Source + +- [github.com/aixgo-dev/sync](https://github.com/aixgo-dev/sync) (Apache-2.0, v0.1.0) +- [github.com/aixgo-dev/sync-mcp](https://github.com/aixgo-dev/sync-mcp) (Apache-2.0) diff --git a/data/aixgate.yaml b/data/aixgate.yaml index 33c6a01..4bf2e5a 100644 --- a/data/aixgate.yaml +++ b/data/aixgate.yaml @@ -7,6 +7,12 @@ repo: "https://github.com/aixgo-dev/aixgate" release: "v0.1" +cta: + primary_text: "Install it" + primary_href: "#install" + heading: "Wrap your agent and try to read a secret." + sub: "That is the whole test, and it takes about a minute." + hero: eyebrow: "Aixgate · Open source · MIT" status: >- diff --git a/data/products.yaml b/data/products.yaml index 5c805a2..5c5570f 100644 --- a/data/products.yaml +++ b/data/products.yaml @@ -1,6 +1,7 @@ -# The sibling products surfaced on the homepage "Also from us" band and in the -# footer's Products column. Add an entry here rather than building another -# one-off section in layouts/index.html. +# The sibling products surfaced on the homepage "Also from us" band, the +# /products/ hub (after the hardcoded Framework card), and llms.txt. +# Add an entry here rather than building another one-off section in +# layouts/index.html. The footer Products column is still hardcoded. - name: "Code" url: "/code/" @@ -16,3 +17,10 @@ Aider or OpenAI Codex without giving them your .env, ~/.aws or ~/.ssh, blocked at the syscall boundary, even under prompt injection. status: "v0.1 proof of concept · MIT" + +- name: "Sync" + url: "/sync/" + description: >- + A coordination plane for sessions, messages and jobs. MCP clients reach + it through sync-mcp. + status: "v0.1.0 · Apache-2.0" diff --git a/data/sync.yaml b/data/sync.yaml new file mode 100644 index 0000000..323a000 --- /dev/null +++ b/data/sync.yaml @@ -0,0 +1,71 @@ +# Sync product page (/sync/). +# +# Claims here trace to github.com/aixgo-dev/sync README.md and +# github.com/aixgo-dev/sync-mcp README.md. If a fact is not in those +# READMEs, it does not belong on the page. + +repo: "https://github.com/aixgo-dev/sync" +release: "v0.1.0" + +hero: + eyebrow: "Sync · Open source · Apache-2.0" + status: >- + v0.1.0. Sessions, messages and jobs with compare-and-swap, on memory + or S3-compatible storage. You host it. Session attach and Code offload + are not in this release. MCP clients use sync-mcp against the same API. + +stats: + - value: "CAS" + label: "JSON objects with If-Match / ETag" + accent: true + - value: "org/project" + label: "Tenant path and API-key scope" + accent: true + - value: "stdio" + label: "sync-mcp talks MCP, then HTTP to Sync" + - value: "Apache-2.0" + label: "Open source licence" + +cta: + primary_text: "Run it" + primary_href: "#run" + heading: "Run a local Sync." + sub: "One process, a tenant key, then optional sync-mcp on stdio." + +security_heading: "Tenant keys, and what they do not cover." +security_intro: >- + Keys are bound to one org and project. Sync stores and claims jobs. + It does not sandbox workers or execute payloads. + +defends: + - "A token is bound to one org and project. A path outside that tenant returns 403." + - "Every route except GET /healthz needs a known key. Unknown paths do not leak as 404 without a key." + - "MCP org and project are fixed at start. Tools have no tenant arguments. --read-only drops write and claim tools." + +cannot: + - "Process or syscall sandboxing. That is Aixgate, a separate product." + - "Executing or inspecting job payloads. A worker that claims the job is what runs it." + - "Encrypting stored JSON, terminating TLS on the listen socket, OIDC, quotas, or an audit log." + - "Prompt injection. Message, label and job fields are untrusted data." + +roadmap: + - version: "v0.1.0" + state: "done" + item: "CAS store, tenant keys, HTTP sessions, messages and jobs" + - version: "next" + state: "progress" + item: "Desired-state GET/PUT, session attach, device register" + - version: "later" + state: "todo" + item: "Notify plane, Code offload contract, Cloudflare Containers runbook" + +links: + - text: "Sync repository" + url: "https://github.com/aixgo-dev/sync" + note: "Source, issues and releases" + - text: "sync-mcp" + url: "https://github.com/aixgo-dev/sync-mcp" + note: "MCP stdio server" + - text: "Product requirements" + url: "https://github.com/aixgo-dev/sync/blob/main/docs/PRD.md" + note: "The Sync PRD" diff --git a/layouts/404.html b/layouts/404.html index 215eb9a..9429f6e 100644 --- a/layouts/404.html +++ b/layouts/404.html @@ -26,6 +26,7 @@

That page is not here.

Aixgo

The agent framework, and where the quick start lives.

Code

An autonomous coding agent that runs in your own GitHub.

Aixgate

A deny-by-default sandbox for AI coding agents.

+

Sync

A coordination plane for sessions, messages and jobs.

Guides

Everything from the quick start to production deployment.

Features

What is implemented, with the numbers that go with it.

Blog

Release notes and what changed in each one.

diff --git a/layouts/_default/_markup/render-codeblock-mermaid.html b/layouts/_default/_markup/render-codeblock-mermaid.html new file mode 100644 index 0000000..e59a62c --- /dev/null +++ b/layouts/_default/_markup/render-codeblock-mermaid.html @@ -0,0 +1,10 @@ +{{/* + Mermaid fences. The generic render-codeblock.html would wrap these in the + copy-button chrome, which is wrong for a diagram. Hugo picks this file + for ```mermaid because of the -mermaid suffix. + + The page store flag loads mermaid.js once, in baseof.html, and only on + pages that actually drew a diagram. +*/}} +{{- .Page.Store.Set "hasMermaid" true -}} +
{{ .Inner | safeHTML }}
diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index c228254..84e3eb5 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -18,5 +18,27 @@ + {{ if .Page.Store.Get "hasMermaid" }} + {{/* Loaded only on pages that rendered a mermaid fence. Pinned ESM, not a + site-wide bundle. Theme tokens match :root in main.css. */}} + + {{ end }} diff --git a/layouts/_default/product.html b/layouts/_default/product.html index 4f75e24..a9c4d67 100644 --- a/layouts/_default/product.html +++ b/layouts/_default/product.html @@ -40,8 +40,10 @@

{{ .Title }}

{{ end }} + {{- $ctaText := $d.cta.primary_text | default "Install it" -}} + {{- $ctaHref := $d.cta.primary_href | default "#install" -}} @@ -74,11 +76,9 @@

{{ .Title }}

●Security model

-

What it stops, and what it does not.

+

{{ $d.security_heading | default "What it stops, and what it does not." }}

- A boundary is only useful if its edges are written down. Both lists - below are on this page for the same reason: so a reviewer can read - them without opening an issue. + {{ $d.security_intro | default "A boundary is only useful if its edges are written down. Both lists below are on this page for the same reason: so a reviewer can read them without opening an issue." }}

@@ -142,11 +142,11 @@

What is next, in order.

-

Wrap your agent and try to read a secret.

+

{{ $d.cta.heading | default "Wrap your agent and try to read a secret." }}

-

That is the whole test, and it takes about a minute.

+

{{ $d.cta.sub | default "That is the whole test, and it takes about a minute." }}

{{ with $d.links }} diff --git a/layouts/_default/products.html b/layouts/_default/products.html new file mode 100644 index 0000000..d67d46a --- /dev/null +++ b/layouts/_default/products.html @@ -0,0 +1,45 @@ +{{/* + /products/ hub. The top nav collapses Code, Aixgate and Sync into this + page once a third sibling product exists (see config/_default/menus.en.toml). + + The framework card is first and hardcoded: data/products.yaml is the + sibling list used on the homepage "Also from us" band, which must not + include a link back to /. +*/}} +{{ define "main" }} +
+ +
+ + +
+
+

→Aixgo · Products

+

{{ .Title }}

+ + {{ with .Description }}

{{ . }}

{{ end }} +
+
+
+ +
+ +
+ +
+{{ end }} diff --git a/layouts/index.html b/layouts/index.html index cb7f206..e02e99d 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -201,10 +201,10 @@

Latest release: {{ $r.tag }} · {{ dateFormat "2 January 2006" $r.date

06Also from us

-

Aixgo builds agents. The other two deal with what agents do next.

+

Aixgo builds agents. Code, Aixgate and Sync handle the rest.

-
+ diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 7e672ce..869f9df 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -52,6 +52,9 @@ {{- else if hasPrefix .RelPermalink "/aixgate" -}} {{- $ctaURL = "/aixgate/#install" -}} {{- $ctaText = "Install" -}} + {{- else if hasPrefix .RelPermalink "/sync" -}} + {{- $ctaURL = "/sync/#run" -}} + {{- $ctaText = "Run it" -}} {{- end }}