diff --git a/content/sync.md b/content/sync.md index 8b33b93..4103694 100644 --- a/content/sync.md +++ b/content/sync.md @@ -14,6 +14,14 @@ The default store is in memory and is lost on restart. Set `SYNC_S3_BUCKET` (and Sync does not run agents, merge pull requests, or execute jobs. Workers that claim a job are what run the payload. +## Compare-and-swap + +CAS is compare-and-swap. Sync keeps JSON documents, not rows in a SQL database. Each document has an ETag, a version stamp from the last write. + +An update sends that stamp as `If-Match`. The write succeeds only if the document is still the version you read. If another worker wrote first, Sync returns `412` and you read again. + +That is how two agents can share a session or claim a job without silently overwriting each other. + ## 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. diff --git a/data/sync.yaml b/data/sync.yaml index 323a000..ff33d92 100644 --- a/data/sync.yaml +++ b/data/sync.yaml @@ -16,7 +16,7 @@ hero: stats: - value: "CAS" - label: "JSON objects with If-Match / ETag" + label: "Compare-and-swap: a write is rejected if the document changed since you read it" accent: true - value: "org/project" label: "Tenant path and API-key scope" @@ -51,7 +51,7 @@ cannot: roadmap: - version: "v0.1.0" state: "done" - item: "CAS store, tenant keys, HTTP sessions, messages and jobs" + item: "Compare-and-swap store, tenant keys, HTTP sessions, messages and jobs" - version: "next" state: "progress" item: "Desired-state GET/PUT, session attach, device register" diff --git a/layouts/_default/products.html b/layouts/_default/products.html index d67d46a..9e8270b 100644 --- a/layouts/_default/products.html +++ b/layouts/_default/products.html @@ -25,13 +25,13 @@
The Go framework for building agents. One module, one binary.
MIT
{{- range hugo.Data.products }} - +{{ .description }}
{{ .status }}
diff --git a/layouts/index.html b/layouts/index.html index e02e99d..1f04f44 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -206,7 +206,7 @@{{ .description }}
{{ .status }}
diff --git a/static/css/main.css b/static/css/main.css index 919e17b..1c13127 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -431,6 +431,7 @@ border-radius: var(--ax-r-lg); padding: var(--ax-s-5); box-shadow: var(--ax-e-1); + overflow-wrap: break-word; transition: border-color var(--ax-dur-1) var(--ax-ease), box-shadow var(--ax-dur-2) var(--ax-ease), diff --git a/static/css/sections.css b/static/css/sections.css index 7b74e93..07643c7 100644 --- a/static/css/sections.css +++ b/static/css/sections.css @@ -152,6 +152,10 @@ letter-spacing: -0.028em; line-height: 1.04; color: var(--ax-text); + /* Global h1 uses text-wrap: balance, which will keep a short title on + one line even when it overflows. The hero clips overflow, so wrap. */ + text-wrap: wrap; + overflow-wrap: break-word; } .ax-hero .ax-rule { margin-top: 1.25rem; } @@ -955,6 +959,7 @@ .ax-listcard { display: block; text-decoration: none; + color: inherit; } .ax-listcard__meta { margin-bottom: var(--ax-s-3); }