Skip to content
Open
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
343 changes: 0 additions & 343 deletions .github/workflows/spec-drift-fix.yml

This file was deleted.

164 changes: 0 additions & 164 deletions .github/workflows/spec-drift-watch.yml

This file was deleted.

18 changes: 5 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,13 @@ A partner list is not adoption, and a transaction count is not commerce. If a nu
- Put the spec first in `links`.
- Change `last_verified` only when you have rechecked **every** claim on the page.

## Spec sources
## Which spec a page describes

Every standard lists where its spec lives in `spec_sources`, with a `pin`: the exact state of the spec that was read (a Git SHA, a release tag, a draft revision, or a digest of a page's text). Once a week a check ([`scripts/spec-drift.mjs`](scripts/spec-drift.mjs), run by [`spec-drift-watch.yml`](.github/workflows/spec-drift-watch.yml)) compares each spec with its pins. When one changed, it opens an issue that links what changed, and the standard's page says "The spec changed after this check" until the pins move. The template lists the kinds of source.
Every standard names its spec with `spec`, an id from the [Ora spec registry](https://github.com/ora/specs) (`specs/<id>/spec.yaml` there). The registry, not this repository, records each spec's versions, where it lives and the exact state Ora last reviewed, and it ships to this site as the `@ora-ai/specs` package. Every [`/specs`](https://ax.guide/specs) row, [`/specs.json`](https://ax.guide/specs.json) and `/specs/<id>.json` come from it.

An issue still open after 14 days gets the `spec-drift-overdue` label and a comment that mentions a maintainer. If the run itself fails, it opens a separate issue, which closes after the next good run.
Once a day the registry's watch compares each spec with its reviewed state. When one changed, it opens an issue on the registry that links what changed, and the standard's page here says "The spec changed after its last review" until the registry moves its pins. To track a spec the registry does not list yet, or to report a change it missed, open an issue or a pull request on [ora/specs](https://github.com/ora/specs).

When the repository has a Claude key (`ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN` secret), each new issue also starts [`spec-drift-fix.yml`](.github/workflows/spec-drift-fix.yml). It opens a pull request that moves the pins and carries Claude's review of the change: what changed, which claims on the page still hold, and suggested edits with sources. Claude only writes that review (it reads files, with no shell, web access or GitHub token), so make the edits on the pull request's branch yourself, after checking them. A newer dated revision (ACP's spec folders) is never adopted automatically; the review is posted on the issue instead. Close and reopen that pull request to run CI on it. You can start the workflow by hand for any open drift issue from the Actions tab.

When you handle one of those issues yourself:

1. Read what changed and recheck the page against it.
2. Set each moved `pin` to the live value the issue lists, even when nothing on the page needed to change: moving a pin is the record that someone read the change.
3. Run `npm run pins`. It regenerates [`spec-pins.json`](spec-pins.json), which the check reads, and the tests fail until it matches the content files.

To see the live state yourself, run `node scripts/spec-drift.mjs check spec-pins.json --only <id>`. It needs Node and Git, no install. [Ora](https://ora.ai) reads `spec-pins.json` too and compares it with the pins behind its own checks, so tell us in the pull request if a change looks like it should change how sites are scored.
The page's own check stays here: change `last_verified` only when you rechecked every claim on the page. A spec change upstream is a reason to recheck, so a drift note is a good place to start a correction.

## House style

Expand Down Expand Up @@ -91,7 +83,7 @@ npm test
npm run build
```

If you added a standard or changed a name or a `phrase`, run `npm run readme` too: it regenerates the table of standards in the README, and the tests fail until it matches. If you changed `spec_sources`, run `npm run pins` for the same reason.
If you added a standard or changed a name or a `phrase`, run `npm run readme` too: it regenerates the table of standards in the README, and the tests fail until it matches.

## License of contributions

Expand Down
33 changes: 33 additions & 0 deletions app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { content } from "@/lib/content";
import { currentSiteUrl } from "@/lib/site-url";
import { getStandards } from "@/lib/standards";

// Built from the content files at build time; nothing in it changes between deploys.
export const dynamic = "force-static";

/** A short index of the site for agents: one link per page, with a clause each. */
export function GET() {
const base = currentSiteUrl().origin;
const lines = [
`# ${content.siteName}`,
"",
`> ${content.metadata.description}`,
"",
"## Standards",
"",
...getStandards().map((s) => `- [${s.name}](${base}/standards/${s.id}): ${s.phrase}`),
"",
"## Pages",
"",
`- [Compare](${base}/compare): every standard side by side, grouped by job`,
`- [Which one?](${base}/which): which standard fits a situation`,
`- [Specs](${base}/specs): each spec's versions, the version Ora reviewed, and the latest upstream`,
"",
"## Data",
"",
`- [specs.json](${base}/specs.json): the spec registry as JSON; one spec at /specs/<id>.json`,
`- [Spec registry](${content.repo.specsUrl}): the source repository, also published as @ora-ai/specs on npm`,
"",
];
return new Response(lines.join("\n"), { headers: { "Content-Type": "text/plain; charset=utf-8" } });
}
2 changes: 1 addition & 1 deletion app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
const base = currentSiteUrl();
const at = (path: string) => new URL(path, base).toString();
return [
...["/", "/compare", "/which", "/contribute"].map((path) => ({ url: at(path) })),
...["/", "/compare", "/which", "/specs", "/contribute"].map((path) => ({ url: at(path) })),
...getStandards().map((s) => ({ url: at(`/standards/${s.id}`), lastModified: s.last_verified })),
];
}
13 changes: 13 additions & 0 deletions app/specs.json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { currentSiteUrl } from "@/lib/site-url";
import { getSpecStatus, specsDocument } from "@/lib/specs";

// Made again at most hourly (SPEC_STATUS_REVALIDATE), like /specs.
export const revalidate = 3600;

/** Every spec in the registry: its versions, Ora's reviewed version and the latest upstream. */
export async function GET() {
const site = currentSiteUrl().origin;
return Response.json(specsDocument(await getSpecStatus(), site), {
headers: { "Access-Control-Allow-Origin": "*" },
});
}
25 changes: 25 additions & 0 deletions app/specs/[file]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { SPEC_IDS } from "@ora-ai/specs";
import { currentSiteUrl } from "@/lib/site-url";
import { getSpecStatus, isSpecId, specsDocument } from "@/lib/specs";

type Props = { params: Promise<{ file: string }> };

// One file per registry id, made at build time and again at most hourly (SPEC_STATUS_REVALIDATE).
export const dynamicParams = false;
export const revalidate = 3600;

export function generateStaticParams() {
return SPEC_IDS.map((id) => ({ file: `${id}.json` }));
}

/** One spec, in the same shape as an entry of /specs.json. */
export async function GET(_request: Request, { params }: Props) {
const id = (await params).file.replace(/\.json$/, "");
if (!isSpecId(id)) return new Response("Not found", { status: 404 });
const doc = specsDocument(await getSpecStatus(), currentSiteUrl().origin);
const spec = doc.specs.find((s) => s.id === id);
return Response.json(
{ registry: doc.registry, checked_at: doc.checked_at, spec },
{ headers: { "Access-Control-Allow-Origin": "*" } },
);
}
Loading
Loading