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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -198,6 +198,7 @@ For Cloudflare Pages deploys, env vars are set in the Pages project settings (no
- Live site: <https://aixgo.dev>
- Framework repo: <https://github.com/aixgo-dev/aixgo>
- Sandbox companion: <https://github.com/aixgo-dev/aixgate>
- Coordination plane: <https://github.com/aixgo-dev/sync>
- Hugo docs: <https://gohugo.io/documentation/>
- Cloudflare Pages docs: <https://developers.cloudflare.com/pages/>

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
15 changes: 5 additions & 10 deletions config/_default/menus.en.toml
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
8 changes: 8 additions & 0 deletions content/products.md
Original file line number Diff line number Diff line change
@@ -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"
---

<!-- Front matter only. The cards come from data/products.yaml plus the
framework entry in layouts/_default/products.html. -->
58 changes: 58 additions & 0 deletions content/sync.md
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 6 additions & 0 deletions data/aixgate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: >-
Expand Down
14 changes: 11 additions & 3 deletions data/products.yaml
Original file line number Diff line number Diff line change
@@ -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/"
Expand All @@ -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"
71 changes: 71 additions & 0 deletions data/sync.yaml
Original file line number Diff line number Diff line change
@@ -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"
1 change: 1 addition & 0 deletions layouts/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ <h1 class="ax-hero__title">That page is not here.</h1>
<a class="ax-card ax-listcard" href="/"><h2>Aixgo</h2><p>The agent framework, and where the quick start lives.</p></a>
<a class="ax-card ax-listcard" href="/code/"><h2>Code</h2><p>An autonomous coding agent that runs in your own GitHub.</p></a>
<a class="ax-card ax-listcard" href="/aixgate/"><h2>Aixgate</h2><p>A deny-by-default sandbox for AI coding agents.</p></a>
<a class="ax-card ax-listcard" href="/sync/"><h2>Sync</h2><p>A coordination plane for sessions, messages and jobs.</p></a>
<a class="ax-card ax-listcard" href="/guides/"><h2>Guides</h2><p>Everything from the quick start to production deployment.</p></a>
<a class="ax-card ax-listcard" href="/features/"><h2>Features</h2><p>What is implemented, with the numbers that go with it.</p></a>
<a class="ax-card ax-listcard" href="/blog/"><h2>Blog</h2><p>Release notes and what changed in each one.</p></a>
Expand Down
10 changes: 10 additions & 0 deletions layouts/_default/_markup/render-codeblock-mermaid.html
Original file line number Diff line number Diff line change
@@ -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 -}}
<pre class="mermaid">{{ .Inner | safeHTML }}</pre>
22 changes: 22 additions & 0 deletions layouts/_default/baseof.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,27 @@

<!-- JavaScript -->
<script src="/js/main.js"></script>
{{ 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. */}}
<script type="module">
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11.12.0/dist/mermaid.esm.min.mjs";
mermaid.initialize({
startOnLoad: true,
theme: "dark",
securityLevel: "strict",
themeVariables: {
background: "#0a0f1c",
primaryColor: "#1a2233",
primaryTextColor: "#cbd5e1",
primaryBorderColor: "#2a3544",
lineColor: "#22d3ee",
secondaryColor: "#141b2d",
tertiaryColor: "#0d1424",
fontFamily: "Inter, sans-serif"
}
});
</script>
{{ end }}
</body>
</html>
16 changes: 8 additions & 8 deletions layouts/_default/product.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ <h1 class="ax-hero__title">{{ .Title }}</h1>
</div>
{{ end }}

{{- $ctaText := $d.cta.primary_text | default "Install it" -}}
{{- $ctaHref := $d.cta.primary_href | default "#install" -}}
<div class="ax-btnrow">
<a class="ax-btn ax-btn--primary" href="#install">Install it &rarr;</a>
<a class="ax-btn ax-btn--primary" href="{{ $ctaHref }}">{{ $ctaText }} &rarr;</a>
<a class="ax-btn ax-btn--secondary" href="{{ $d.repo }}" target="_blank" rel="noopener">Read the source on GitHub &rarr;<span class="sr-only"> (opens in a new tab)</span></a>
</div>
</div>
Expand Down Expand Up @@ -74,11 +76,9 @@ <h1 class="ax-hero__title">{{ .Title }}</h1>
<div class="ax-wrap">
<div class="ax-section__intro">
<p class="ax-eyebrow"><span class="ax-eyebrow__num">&#9679;</span>Security model</p>
<h2>What it stops, and what it does not.</h2>
<h2>{{ $d.security_heading | default "What it stops, and what it does not." }}</h2>
<p>
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." }}
</p>
</div>

Expand Down Expand Up @@ -142,11 +142,11 @@ <h2>What is next, in order.</h2>
<div class="ax-final__halo ax-halo" aria-hidden="true"></div>
<div class="ax-wrap">
<div class="ax-final__body">
<h2>Wrap your agent and try to read a secret.</h2>
<h2>{{ $d.cta.heading | default "Wrap your agent and try to read a secret." }}</h2>
<span class="ax-rule" aria-hidden="true"></span>
<p>That is the whole test, and it takes about a minute.</p>
<p>{{ $d.cta.sub | default "That is the whole test, and it takes about a minute." }}</p>
<div class="ax-btnrow">
<a class="ax-btn ax-btn--primary" href="#install">Install it &rarr;</a>
<a class="ax-btn ax-btn--primary" href="{{ $d.cta.primary_href | default "#install" }}">{{ $d.cta.primary_text | default "Install it" }} &rarr;</a>
<a class="ax-btn ax-btn--secondary" href="{{ $d.repo }}" target="_blank" rel="noopener">Read the source &rarr;<span class="sr-only"> (opens in a new tab)</span></a>
</div>
{{ with $d.links }}
Expand Down
45 changes: 45 additions & 0 deletions layouts/_default/products.html
Original file line number Diff line number Diff line change
@@ -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" }}
<div class="ax-page">

<section class="ax-section ax-hero ax-hero--compact">
<div class="ax-hero__halo ax-halo" aria-hidden="true"></div>
<div class="ax-hero__grid ax-dotgrid ax-dotgrid--fade" aria-hidden="true"></div>
<div class="ax-wrap">
<div class="ax-hero__body ax-edge ax-edge--section">
<p class="ax-eyebrow"><span class="ax-eyebrow__num">&rarr;</span>Aixgo · Products</p>
<h1 class="ax-hero__title">{{ .Title }}</h1>
<span class="ax-rule ax-rule--wide" aria-hidden="true"></span>
{{ with .Description }}<p class="ax-hero__sub">{{ . }}</p>{{ end }}
</div>
</div>
</section>

<section class="ax-section ax-section--alt ax-textured">
<div class="ax-wrap">
<div class="ax-grid ax-grid--2">
<a class="ax-card sibling-card" href="/">
<h2>Framework</h2>
<p>The Go framework for building agents. One module, one binary.</p>
<p class="ax-microlabel sibling-status">MIT</p>
</a>
{{- range hugo.Data.products }}
<a class="ax-card sibling-card" href="{{ .url }}">
<h2>{{ .name }}</h2>
<p>{{ .description }}</p>
<p class="ax-microlabel sibling-status">{{ .status }}</p>
</a>
{{- end }}
</div>
</div>
</section>

</div>
{{ end }}
4 changes: 2 additions & 2 deletions layouts/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ <h2>Latest release: {{ $r.tag }} &middot; {{ dateFormat "2 January 2006" $r.date
<div class="ax-wrap">
<div class="ax-section__intro">
<p class="ax-eyebrow"><span class="ax-eyebrow__num">06</span>Also from us</p>
<h2>Aixgo builds agents. The other two deal with what agents do next.</h2>
<h2>Aixgo builds agents. Code, Aixgate and Sync handle the rest.</h2>
</div>

<div class="ax-grid ax-grid--2">
<div class="ax-grid ax-grid--3">
{{- range hugo.Data.products }}
<a class="ax-card sibling-card" href="{{ .url }}">
<h3>{{ .name }}</h3>
Expand Down
2 changes: 1 addition & 1 deletion layouts/index.llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Every link below is read out of this site's own pages and data files when the si
{{- end }}
## About the framework

{{ $productURLs := slice -}}
{{ $productURLs := slice "/products/" -}}
{{- range hugo.Data.products }}{{ $productURLs = $productURLs | append .url }}{{ end -}}
{{- range (where site.RegularPages "Section" "").ByTitle -}}
{{- if not (in $productURLs .RelPermalink) -}}
Expand Down
1 change: 1 addition & 0 deletions layouts/partials/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ <h2 class="footer-heading">Products</h2>
<li><a href="/">Aixgo <span class="footer-note">the agent framework</span></a></li>
<li><a href="/code/">Code <span class="footer-note">an agent in your GitHub</span></a></li>
<li><a href="/aixgate/">Aixgate <span class="footer-note">a sandbox for coding agents</span></a></li>
<li><a href="/sync/">Sync <span class="footer-note">a coordination plane</span></a></li>
<li><a href="https://github.com/aixgo-dev/aixgo/releases" target="_blank" rel="noopener noreferrer">Changelog</a></li>
</ul>
</div>
Expand Down
Loading
Loading