Codync
免費、開源的 1:1 替代方案,取代 Grok Bot 與 Muse。從 iPhone、Mac 或 Linux 桌面將 Claude Code、Codex、Cursor 與 40+ 程式碼代理人作為持續機器人傳訊。群組聊天、主題串…
AI 翻譯
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗An open source website quality engine. It crawls 5–20 domains slowly and politely across each week, scans thousands of pages per domain with axe-core and Siteimprove Alfa (the open source engine behind Siteimprove's commercial checker), measures page weight, estimated energy costs, image inventory, and technology stack, and publishes week-over-week reports to GitHub Pages. Everything runs on GitHub Actions. There is no server, no database, and no budget line.
Continuous measurement beats one-off audits. The question this answers is not "is this site accessible?" but "is this site getting more accessible to more people?"
Files are the only state. Data is append-only. Reports are pure functions of the data directory.
state/<domain>/crawl.json: the crawl frontier. The only mutable
file. Not committed: CI keeps it on the scan-state release (see
ARCHITECTURE.md). If it is deleted, the crawler reseeds from the sitemap
and no history is lost.data/: scan data. Not tracked in this repo: it is its own repo
(data_repo in config/targets.yml, default
mgifford/vital-core-data),
checked out into data/ by CI. Clone it there locally only when you need
the data; the code runs and tests without it.data/<domain>/<ISO-week>/pages/*.json: one compact record per page
per week. Append-only.data/<domain>/<ISO-week>/runs/*.json: append-only run logs.data/<domain>/<ISO-week>/summary.json: the weekly rollup, computed
from the page records and committed. Old page-level detail is pruned
after retention_weeks; summaries are kept forever, so trend history
never breaks.docs/: generated HTML, built at deploy time and shipped as a Pages
artifact. Never committed. It cannot drift from the data because
it does not persist.Other deliberate choices:
src/lib/urls.js) defines page identity everywhere. Week-over-week
comparison depends on it; treat it as a frozen contract.#finding anchors) never break.settle_delay_ms, overridable
with VITAL_A11Y_SETTLE_DELAY_MS) lets client-side hydration finish,
which removes the largest source of transient false positives.url_include / url_exclude
pattern arrays (set in config/targets.yml) narrow which pages are
crawled and scanned. Each pattern is a substring or a /regex/, and long
lists can live in a file via url_include_file / url_exclude_file
(resolved under config/). Priority URLs always bypass the filter..aspx pages)
via a control on the landing and Accessibility pages. The list is a
substring//regex/ set saved per-domain in the browser (localStorage),
shared across both pages, and exportable/importable so a team can agree on
one scope. Scanning is unaffected — it only changes what the report shows;
with JavaScript off the full report renders.scan workflow runs nightly at off-hours (UTC crons in
.github/workflows/scan.yml; adjust for your targets' audiences).pages_per_run pages per domain that have not
yet been scanned this ISO week, discovering new same-host links as it
goes. Coverage accumulates: 300 pages/run × 7 runs ≈ 2,000+
pages/domain/week, within the max_pages_per_week cap.report workflow aggregates the
week, deploys the reports to GitHub Pages, and prunes page-level
detail older than retention_weeks.pdf-audit workflow checks the PDFs each site links to
(daily, for sites with pdf_audit: { enabled: true }, or for one site
from Actions → pdf-audit), and the next report shows them on that
site's PDFs page.For how crawling, storage, and the pipeline work in more detail, see ARCHITECTURE.md.
GitHub is the source of truth for this project. The main branch keeps
the full working history, and that is where development should land.
Hugging Face Spaces has been archived. It was a deployment target, not a second source branch:
it should receive a clean snapshot of the current site state on its own
main branch, with large state/ crawl artifacts stripped out before
push.
An instance is two repositories: this code (the workflows, config/) and a
companion data repository that CI commits scan results to. Every step
below is needed; a missing one tends to fail quietly, late in a run.
Create the code repo from the template, then join its history to
upstream. This repository is a GitHub template: choose Use this
template → Create a new repository, leaving "Include all branches"
unticked. GitHub starts the new repo with one "Initial commit" that
copies these files but not their history, so git merge upstream/main
can't work until the two histories are joined. Join them once, straight
away. It changes no files:
git clone [email protected]:<owner>/<name>.git
cd <name>
git remote add upstream https://github.com/mgifford/vital-core
git fetch upstream main
# The upstream commit that "Initial commit" was copied from:
ROOT_TREE=$(git rev-parse "$(git rev-list --max-parents=0 HEAD)^{tree}")
BASE=$(git log --format='%H %T' upstream/main | awk -v t="$ROOT_TREE" '$2 == t { print $1; exit }')
if [ -n "$BASE" ]; then
git merge -s ours --allow-unrelated-histories "$BASE" \
-m "Record vital-core ${BASE:0:7} as upstream base"
git push
else
echo "No upstream commit matches the initial commit." >&2
fi
If no commit matches, the first commit isn't an unchanged copy of an
upstream commit, so don't guess one. Never run the -s ours merge
against upstream/main itself: it records every upstream change made
since the copy as merged without applying it.
Instead of the template, you can clone this repository and push it to a
new, empty repo (git remote rename origin upstream, then add your repo
as origin). That keeps the shared history from the start, with no join
step.
A repo made from the template has the scheduled scan and report
workflows switched on from its first commit, with this repo's targets in
config/targets.yml. Until step 4 they stop at the push-access check
without fetching any site, so finish step 3 before adding the key.
Create the data repo: a public repository such as <name>-data,
with an initial commit (a README is enough). It must be public: the
report's gate job reads its marker files with the workflow's own token.
Edit config/targets.yml:
data_repo: to the data repouser_agent contact URL at your reporeport_base_url: to https://<owner>.github.io/<name>; CSV
links, llms.txt and the API catalog are built from itfinding_policy.conformance (the WCAG target) and, where a law
sets a lower minimum, legal_baseline (for US federal sites, Section
508: WCAG 2.0 AA). The shipped default is Section 508, so change or
remove it for any other jurisdictiongit fetch upstream main
git merge upstream/main
Conflicts should only appear in files you changed yourself. A fix that
reached both repos by copying rather than merging (for example, one you
made in your repo and then ported upstream) can conflict once. Take
upstream's version (git checkout --theirs <file>) unless you meant to keep
yours. For package-lock.json, take upstream's version, then run npm ci
to confirm it still matches package.json.
Keep a docs-internal/UPSTREAM-SUGGESTIONS.md in your repo for anything
every instance would want: an engine bug, a US-only assumption, a missing
setup step. vital-core never ships that file, so it never conflicts. Fix
those things in vital-core, on a branch from upstream/main, then merge
upstream into your repo. See CLAUDE.md, "Fleets made from this template".
npm ci
npx playwright install chromium
node src/scan.js --domain example.gov --budget 25
node src/aggregate.js
npx http-server docs # or open docs/index.html
Tests:
npm run test:unit # URL identity, ISO weeks, robots.txt, batch picking
npm run test:e2e # full pipeline over a local fixture site simulating two weeks
Reports can be published in multiple languages. Set languages (and optionally
default_language) in config/targets.yml — globally or per target, e.g.
languages: [en, fr] for a Canadian site. The default language keeps the usual
file paths; every other language is published alongside as <page>-<lang>.html,
cross-linked by a header language switcher that works without JavaScript. A
reader's choice is remembered in localStorage and can be forced from a link
with ?lang=<code> (e.g. ?lang=fr); both are progressive enhancement and are
only active when more than one language is configured.
Translation uses a Drupal/gettext-style t() where the English phrase is the
key, so untranslated strings fall back to English and partial catalogs are safe.
Catalogs are human-reviewed JSON in src/locales/<lang>.json (en, fr, ja,
nl supported). Run npm run i18n:extract to refresh the translator checklist
(src/locales/template.json). Only the UI chrome is translated — engine-sourced
WCAG/rule descriptions stay English. See CLAUDE.md for details.
Every build publishes a static, read-only, versioned JSON API next to the HTML
reports at /api/v1/ — no server, database, or auth. Consume it with a plain
HTTP GET (curl, fetch, CI) instead of scraping HTML. Endpoints: an
index.json of all domains, a per-domain snapshot.json, and per-week
findings.json, each carrying a schema_version and validated against
published JSON Schemas. URLs are redacted for publication (fragments stripped,
sensitive query values [REDACTED]) and excluded pages are omitted. See
API.md for the full contract, schemas, retention, and examples.
Every deployed site also publishes /llms.txt (the
llmstxt.org convention): a plain-text index pointing
an LLM or coding agent at the JSON API, API.md, and MCP.md, so the data
behind the HTML report is discoverable without already knowing this
repository exists.
mcp/ is a local, read-only-by-default Model Context Protocol
server that lets an MCP-compatible coding client (Claude Code, GitHub
Copilot, etc.) list and inspect findings from a Vital Core instance's JSON
API. It runs on your own machine over stdio — no network port, no local
repository access, no command execution. See MCP.md for setup,
.vital.yml, the available tools, and what's intentionally not implemented
yet.
A separate, opt-in WebMCP bridge registers the same read-only tools directly in a domain's report pages, for an in-browser agent instead of a local coding client — see MCP.md#webmcp.
The crawler honors robots.txt (Disallow/Allow/Crawl-delay),
identifies itself with a user agent containing a contact URL, scans one
page at a time per domain with a configurable delay, and runs at night.
PDF checks follow the same rules: one PDF at a time, only from the site's
own domain, each downloaded once and then re-validated with a conditional
request at most every 90 days.
If you operate a site being scanned and want changes, open an issue.
This project follows public commitments to accessibility and sustainability, and aims to advance the W3C Web Sustainability Guidelines. The reports themselves are part of the argument: semantic HTML, no web fonts, ~2 KB of CSS, dark mode respected. They work fully without JavaScript — every chart renders as a static SVG with a data-table fallback. Where JavaScript is available, charts are progressively enhanced into interactive, keyboard- and screen-reader-navigable ParaCharts, vendored and served first-party (no CDN).
AGPL-3.0. Vendored third-party components: the
HTTPArchive/wappalyzer
fingerprint database (GPL-3.0, vendor/wappalyzer/, refreshed via
scripts/update-wappalyzer.sh) and the
ParaCharts accessible-charts
runtime (AGPL-3.0, vendor/paracharts/, refreshed via
scripts/update-paracharts.sh).
languages: down to the ones your readers need. Every listed
language is built and deployed on each report run, even with the
switcher hiddenRun npm run test:unit before pushing; it fails on a config that
doesn't load.
Add a deploy key so CI can push scan data:
ssh-keygen -t ed25519 -N "" -C "<name> Actions" -f data-keydata-key.pub to the data repo → Settings → Deploy keys, with
Allow write access tickeddata-key file, including its BEGIN/END lines, to the
code repo → Settings → Secrets and variables → Actions, as the
repository secret VITAL_DATA_DEPLOY_KEYWithout the key, checkout quietly falls back to a read-only token. The "Check data repo push access" step now stops the run first, and its annotation names the cause.
In the code repo's settings:
Run the first scan: Actions → scan → Run workflow, with the domain
left blank, a small budget (e.g. 10) and Run report ticked. Start one
scan at a time: the scan-global concurrency group keeps only the
newest waiting run and cancels the others.
Check that it really worked. A green run alone doesn't prove anything was scanned. Look for:
https://<owner>.github.io/<name>/A site the scanner couldn't get into is listed at the top of the
dashboard under "Sites blocking the scanner", with the cause: a firewall
rule, robots.txt or no connection. For the details, run Actions →
diagnose with that domain. It shows what the site sends
the scanner from GitHub's network: each redirect hop, the firewall or CDN
in front of it, whether a desktop browser gets a different answer,
robots.txt and the sitemap, and what a slow homepage was still loading.
Locally, npm run diagnose -- <domain> does the same from your network.