Skip to content

Commit 478e1b7

Browse files
authored
Merge pull request #1544 from mnfst/chore/sync-dockerhub-description
ci: auto-sync docker hub description from docker/DOCKER_README.md
2 parents 96035c7 + e4b0e66 commit 478e1b7

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

.github/workflows/docker.yml

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ on:
77
description: "Optional version override (e.g. 5.38.1). Leave blank to use the current version from packages/manifest/package.json."
88
required: false
99
type: string
10+
push:
11+
branches: [main]
12+
paths:
13+
- "docker/DOCKER_README.md"
14+
- ".github/workflows/docker.yml"
1015
pull_request:
1116
branches: [main]
1217
paths:
1318
- "docker/Dockerfile"
1419
- ".dockerignore"
1520
- "docker/docker-compose.yml"
16-
- "docker/DOCKER_README.md"
1721
- "packages/backend/**"
1822
- "packages/frontend/**"
1923
- "packages/shared/**"
@@ -110,3 +114,32 @@ jobs:
110114
for tag in ${TAGS}; do
111115
cosign sign --yes "${tag}@${DIGEST}"
112116
done
117+
118+
sync-description:
119+
name: Sync Docker Hub description
120+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
121+
runs-on: ubuntu-latest
122+
steps:
123+
- uses: actions/checkout@v4
124+
125+
- name: Push README to Docker Hub
126+
env:
127+
DOCKER_USER: ${{ secrets.DOCKERHUB_USERNAME }}
128+
DOCKER_PASS: ${{ secrets.DOCKERHUB_TOKEN }}
129+
run: |
130+
# Pinned to immutable digest for supply-chain safety.
131+
# The underlying tool is chko/docker-pushrm:1. When bumping the tag,
132+
# fetch the current digest with:
133+
# TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:chko/docker-pushrm:pull" | jq -r .token)
134+
# curl -sI -H "Authorization: Bearer $TOKEN" \
135+
# -H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
136+
# https://registry-1.docker.io/v2/chko/docker-pushrm/manifests/1 | grep -i docker-content-digest
137+
docker run --rm \
138+
-v "$GITHUB_WORKSPACE/docker/DOCKER_README.md:/data/README.md:ro" \
139+
-e DOCKER_USER \
140+
-e DOCKER_PASS \
141+
chko/docker-pushrm@sha256:812a950e5be7dca26cef33b61eb2076bfcfb6c2a8ec96c126371fc049c3b6608 \
142+
--file /data/README.md \
143+
--short "Smart LLM router for personal AI agents. Cut costs up to 70%." \
144+
--debug \
145+
manifestdotbuild/manifest

CLAUDE.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,18 +506,24 @@ Changesets are **not** required on every PR — they're optional and only meanin
506506

507507
1. Merge the pending `chore: version packages` PR to land the version bump in `packages/manifest/package.json`.
508508
2. Go to **GitHub Actions → Docker → Run workflow**, leave the `version` input blank, click Run.
509-
3. The `publish` job reads `packages/manifest/package.json`, resolves the version automatically, and pushes `manifestdotbuild/manifest:{version}` + `{major}.{minor}` + `{major}` + `sha-<short>` to Docker Hub. The image is multi-arch (amd64 + arm64) and cosign-signed.
509+
3. The `publish` job reads `packages/manifest/package.json`, resolves the version automatically, and pushes `manifestdotbuild/manifest:{version}` + `{major}.{minor}` + `{major}` + `sha-<short>` to Docker Hub. The image is multi-arch (amd64 + arm64) and cosign-signed. The `sync-description` job also runs in the same workflow_dispatch and pushes the latest `docker/DOCKER_README.md` to the Docker Hub repo description.
510510

511511
To retag an older commit or publish a hotfix version that doesn't match the current `package.json`, pass a semver string in the `version` input and it overrides the package.json lookup.
512512

513+
### Docker Hub description
514+
515+
`docker/DOCKER_README.md` is the source of truth for the Docker Hub repo description at [`manifestdotbuild/manifest`](https://hub.docker.com/r/manifestdotbuild/manifest). The `sync-description` job in `docker.yml` pushes it to Docker Hub via the [`chko/docker-pushrm`](https://github.com/christian-korneck/docker-pushrm) container image (standalone `docker run`, no third-party GitHub Action). It uses the same `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` secrets as the publish job — the Docker Hub PAT needs write access to the repo, which the existing token already has for image pushes. Edits to `docker/DOCKER_README.md` are treated as doc-only: they do **not** trigger the PR validate job (no point rebuilding multi-arch images for content changes), and they auto-sync to Docker Hub on merge to main via a dedicated `push:` trigger with a narrow paths filter. The `chko/docker-pushrm` image is pinned to an immutable digest in the workflow — when bumping, re-fetch the digest via `docker manifest inspect chko/docker-pushrm:1` or the registry API (see the inline comment in `docker.yml`).
516+
513517
### Summary of what CI does on each trigger
514518

515519
| Trigger | What happens |
516520
|---------|--------------|
517-
| PR opened/updated | `ci.yml` runs tests, lint, typecheck, coverage. `docker.yml` validates the Docker build (no push) if the PR touches runtime files. `changeset-check` warns softly if no changeset is present. |
521+
| PR opened/updated (runtime files) | `ci.yml` runs tests, lint, typecheck, coverage. `docker.yml` validates the Docker build (no push). `changeset-check` warns softly if no changeset is present. |
522+
| PR opened/updated (`docker/DOCKER_README.md` only) | No Docker CI runs — content-only change, nothing to validate. |
518523
| Merge to `main` | `release.yml` runs `changesets/action` to open or update the `chore: version packages` PR. **No auto-publish** — neither npm nor Docker. |
519-
| Merge of `chore: version packages` PR | `release.yml` runs again. Version bump in `packages/manifest/package.json` and the CHANGELOG update land on `main`. Still no publish. |
520-
| Manual `workflow_dispatch` on `Docker` workflow | Reads `packages/manifest/package.json` and pushes a new image tag to Docker Hub. This is the **only** path that publishes anything. |
524+
| Merge of `chore: version packages` PR | `release.yml` runs again. Version bump in `packages/manifest/package.json` and the CHANGELOG update land on `main`. Still no image publish. |
525+
| Merge of a PR that touched `docker/DOCKER_README.md` | `docker.yml` `sync-description` job runs, pushing the new README to Docker Hub via `chko/docker-pushrm`. No image rebuild. |
526+
| Manual `workflow_dispatch` on `Docker` workflow | `publish` job reads `packages/manifest/package.json` and pushes a new image tag to Docker Hub. `sync-description` also runs in parallel and re-syncs the Docker Hub description. This is the **only** path that publishes image artifacts. |
521527

522528
## Code Coverage (Codecov)
523529

docker/DOCKER_README.md

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
</picture>
77
</p>
88
<p align="center">
9-
<a href="https://github.com/mnfst/manifest/stargazers"><img src="https://img.shields.io/github/stars/mnfst/manifest?style=flat" alt="GitHub stars" /></a>
9+
<a href="https://hub.docker.com/r/manifestdotbuild/manifest"><img src="https://img.shields.io/docker/pulls/manifestdotbuild/manifest?color=2496ED&label=docker%20pulls" alt="Docker pulls" /></a>
1010
&nbsp;
11-
<a href="https://www.npmjs.com/package/manifest"><img src="https://img.shields.io/npm/v/manifest?color=cb3837&label=npm" alt="npm version" /></a>
11+
<a href="https://github.com/mnfst/manifest/stargazers"><img src="https://img.shields.io/github/stars/mnfst/manifest?style=flat" alt="GitHub stars" /></a>
1212
&nbsp;
1313
<a href="https://github.com/mnfst/manifest/blob/main/LICENSE"><img src="https://img.shields.io/github/license/mnfst/manifest?color=blue" alt="license" /></a>
1414
&nbsp;
@@ -17,17 +17,18 @@
1717

1818
## What is Manifest?
1919

20-
Manifest is a smart model router for OpenClaw. It sits between your agent and your LLM providers, scores each request, and routes it to the cheapest model that can handle it. Simple questions go to fast, cheap models. Hard problems go to expensive ones. You save money without thinking about it.
20+
Manifest is a smart model router for **personal AI agents** like OpenClaw or Hermes. It sits between your agent and your LLM providers, scores each request, and routes it to the cheapest model that can handle it. Simple questions go to fast, cheap models. Hard problems go to expensive ones. You save money without thinking about it.
2121

22-
- Route requests to the right model: Cut costs up to 70%
23-
- Automatic fallbacks: If a model fails, the next one picks up
24-
- Set limits: Don't exceed your budget
22+
- Route requests to the right model: cut costs up to 70%
23+
- Automatic fallbacks: if a model fails, the next one picks up
24+
- Set limits: don't exceed your budget
25+
- Self-hosted: your requests, your providers, your data
2526

26-
![manifest-gh](https://github.com/user-attachments/assets/7dd74fc2-f7d6-4558-a95a-014ed754a125)
27+
![manifest-gh](https://raw.githubusercontent.com/mnfst/manifest/HEAD/.github/assets/manifest-screenshot.png)
2728

2829
## Supported providers
2930

30-
Works with 300+ models across OpenAI, Anthropic, Google Gemini, DeepSeek, xAI, Mistral, Qwen, MiniMax, Kimi, Amazon Nova, OpenRouter, Ollama, and any provider with an OpenAI-compatible API.
31+
Works with 300+ models across OpenAI, Anthropic, Google Gemini, DeepSeek, xAI, Mistral, Qwen, MiniMax, Kimi, Amazon Nova, Z.ai, OpenRouter, Ollama, and any provider with an OpenAI-compatible API. Connect with an API key, or reuse an existing paid subscription (ChatGPT Plus/Pro, Claude Max/Pro, GLM Coding Plan, etc.) where supported.
3132

3233
## Manifest vs OpenRouter
3334

@@ -36,7 +37,7 @@ Works with 300+ models across OpenAI, Anthropic, Google Gemini, DeepSeek, xAI, M
3637
| Architecture | Your Manifest instance forwards to your providers | Cloud proxy. All traffic goes through their servers |
3738
| Cost | Free | 5% fee on every API call |
3839
| Source code | MIT, fully open | Proprietary |
39-
| Data privacy | Metadata only (Cloud), no middleman (self-hosted) | Prompts and responses pass through a third party |
40+
| Data privacy | Self-hosted — no middleman | Prompts and responses pass through a third party |
4041
| Transparency | Open scoring. You see why a model was chosen | No visibility into routing decisions |
4142

4243
---
@@ -121,6 +122,18 @@ environment:
121122
122123
If you see "Invalid origin" on the login page, `BETTER_AUTH_URL` doesn't match the port you're using.
123124

125+
## Image tags
126+
127+
Every release is published with the following tags:
128+
129+
- `{major}.{minor}.{patch}` — fully pinned (e.g. `5.46.0`)
130+
- `{major}.{minor}` — latest patch within a minor (e.g. `5.46`)
131+
- `{major}` — latest minor+patch within a major (e.g. `5`)
132+
- `latest` — latest stable release
133+
- `sha-<short>` — exact commit for rollback
134+
135+
Images are built for both `linux/amd64` and `linux/arm64`.
136+
124137
## Environment variables
125138

126139
| Variable | Required | Default | Description |

0 commit comments

Comments
 (0)