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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ __pycache__/
/.agents/
/.issue-agent/
/ISSUE_AGENT.md

# Documentation site build output.
/apps/docs/.next/
/apps/docs/.source/
/apps/docs/tsconfig.tsbuildinfo
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3665,3 +3665,12 @@ unchanged. Persisted credential encryption domains and native-session resume key
also remain stable so existing data can be decrypted and Sessions can resume.
Conversion inputs, retirement diagnostics and historical evidence must still name
the identifiers they reject or migrate; current examples use the new names.


Core administration error details are scoped by the `/core/v1` router writer mark,
not a request path test. Use `writeCoreError` with typed `CoreErrorDetails` values
and document fixed keys in `contracts/agents-api/core-errors.md` when adding a
code. Include only safe Core-owned facts; never pass submitted values, secrets,
native text or provider bodies. Invalid/empty details are omitted. Preserve the
public and machine error serializers, observer callbacks and streaming interfaces.
The Core client ignores malformed optional details and never retries a mutation.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SWAG_VERSION ?= v1.16.4
help:
@printf '%s\n' 'make build-agents-api Build standalone Core commands' 'make build-daemon Build the execution daemon' 'make check Run Core, persistence and runtime checks' 'See README.md for runtime prerequisites and deployment.'

check: check-names check-distribution check-database check-sqlc check-go check-microsandbox-provider check-agents-api check-claude-sdk check-web check-mcode-harness check-agents-executor
check: check-docs check-names check-distribution check-database check-sqlc check-go check-microsandbox-provider check-agents-api check-claude-sdk check-web check-mcode-harness check-agents-executor
@printf 'OpenAgentCore checks passed.\n'

.PHONY: check-names
Expand Down Expand Up @@ -145,3 +145,7 @@ build-e2b-provider:
check-e2b-provider:
PYTHONDONTWRITEBYTECODE=1 $${OAC_TEST_E2B_SDK_PYTHON:-python3} -m unittest discover -s services/agents-api/deploy/e2b -p '*_test.py'
PYTHONDONTWRITEBYTECODE=1 $${OAC_TEST_E2B_SDK_PYTHON:-python3} -m unittest discover -s services/agents-api/tools/e2b-provider -p '*_test.py'

.PHONY: check-docs
check-docs: node-deps
pnpm check:docs
24 changes: 24 additions & 0 deletions apps/docs/FOLLOW-UP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Feature integration follow-up

This candidate documents the actual maintenance and drain model at source
`75bf4484ba957344ae374354858bbdfe104f5c4f`. It is not final documentation for design 50.
The Core error-envelope foundation is included; the later configuration validators and
diagnostic endpoints are not. Do not replace current procedures with the planned
behavior before the features land.

| Feature dependency | Site pages to reconcile | Source and verification work |
| --- | --- | --- |
| Reset replaces maintenance (design 50 PR-R) | configure, hosted-providers, troubleshooting, admin-api, observability, API reference/core | Regenerate the canonical guides and management contract; describe reset admission, cleanup, failures, archive preconditions and offline-node limits from merged code. Remove retired maintenance instructions only after their replacement exists. |
| Online generations and E2B changes (design 50 PR-G) | configure, hosted-providers, troubleshooting, execution-model, API reference/core | Document actual generation/rollout states, the supported change matrix and existing-sandbox behavior. Verify PUT examples against the final contract. |
| Node update protocol (design 50 PR-N) | hosted-providers, troubleshooting, API reference/machine | Explain the implemented update command, old-node handling and ownership preservation. Do not claim an update command now. |
| Later configuration/error changes (design 40 and remaining installer work) | install, configure, troubleshooting, quickstart | Regenerate current configuration fields and revise diagnostics against merged code; keep secrets out of examples. |
| Final feature assembly | every Chinese reading note, execution-model diagram, all generated references | Review translations against regenerated English, verify source provenance and links, run contract/route/copy/fact checks, typecheck/build, local browser review and the repository gate. |

English guides are rendered from repository sources. Chinese pages are explicitly
labelled reading notes, not complete translations; expand them only against the final
source procedures. API tag pages use the default-language fallback. Release publication,
remote deployment and preview replacement are outside this reconciliation task.

The source Web guide still carries a pre-rename screenshot. This site copies the
approved current Web onboarding Monitor image instead, with its own source hash;
refresh that mapping when the canonical guide image is updated.
48 changes: 48 additions & 0 deletions apps/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# OpenAgentCore documentation site

A separate Next.js/Fumadocs documentation app. It starts no Core, database or Runtime.
English is served at `/`; Chinese reading notes at `/zh`, with English fallback for
API tag pages. The existing preview is not part of this checkout.

The application reference reads the upstream-constrained public schema. Administration
and machine references read their own local generated contracts. All three repository
files currently declare Swagger 2.0; rendering supports Swagger 2 and OpenAPI 3.
The documentation projection uses OpenAPI 3.1 null unions (including nullable references
and compositions). Normalization changes documentation servers and bearer presentation, preserving operation
prose, parameters, response schemas and credential boundaries. Examples use a reserved
domain. The reference is read-only and must not collect keys or send execution requests.

English guides are generated from the canonical repository docs, not maintained as a
second installation manual. Edit those sources first, update the Chinese reading notes
in [guides.json](scripts/guides.json), then regenerate. Source/output hashes fail when
copies drift; operation and route checks detect missing or mixed API surfaces.

From the repository root:

```sh
pnpm install --frozen-lockfile
pnpm --dir apps/docs generate
pnpm --dir apps/docs verify
pnpm --dir apps/docs test
pnpm --dir apps/docs typecheck
pnpm --dir apps/docs build
pnpm --dir apps/docs start --port 4275
```

The route verifier uses the declared `js-yaml` dependency and Python standard library
only; no ambient PyYAML installation is required. Python checks honor
`OAC_TEST_OFFICIAL_SDK_PYTHON` when set, otherwise `python3`, and run with `-S`
to keep site packages out of the gate.

`make check-docs` runs the focused gate and is included in `make check`. After starting
the built site, run `pnpm --dir apps/docs check:site http://127.0.0.1:4275` and inspect
both locales in a browser with `pnpm --dir apps/docs check:browser http://127.0.0.1:4275`.
The check uses installed Playwright Chromium (or `DOCS_BROWSER_EXECUTABLE`), checks
for credential/request controls and external traffic, and accepts only a local origin.
Set `DOCS_SITE_ORIGIN` only when preparing actual publication.
Generation links to the recorded source revision; update that revision after rebasing
onto later canonical guide changes. Never point samples at an actual deployment by default.

[Feature follow-up inventory](FOLLOW-UP.md) lists the reset and online-generation
paragraphs that must be reconciled after those implementations land. This candidate
cannot establish final documentation acceptance for those unfinished features.
78 changes: 78 additions & 0 deletions apps/docs/app/[lang]/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { Metadata } from "next"
import { notFound } from "next/navigation"
import { ImageZoom } from "fumadocs-ui/components/image-zoom"
import defaultMdxComponents from "fumadocs-ui/mdx"
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/page"
import { APIPage } from "@/components/api-page"
import { LocaleLink } from "@/components/locale-link"
import { i18n, type Lang } from "@/lib/i18n"
import { docsAlternates } from "@/lib/site"
import { source } from "@/lib/source"

function asLang(value: string): Lang {
if (!(i18n.languages as readonly string[]).includes(value)) notFound()
return value as Lang
}

function pageSlug(slug?: string[]) {
return slug ?? []
}

export default async function DocsPageRoute({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>
}) {
const { lang: rawLang, slug } = await params
const lang = asLang(rawLang)
const page = source.getPage(pageSlug(slug), lang)
if (!page) notFound()

const MDX = page.data.body
return (
<DocsPage toc={page.data.toc}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<DocsBody>
<MDX
components={{
...defaultMdxComponents,
// Generated API reference pages. Read-only: they render the contract.
APIPage,
// Screenshots open at full size; the prose column is too narrow to
// read a console capture at 1:1.
img: ImageZoom,
// Keep internal navigation inside the reader's language. Pages are
// written with locale-free links — `[Configure](/configure)` — and
// the prefix is added here, because a translated page would
// otherwise silently hand the reader the default language.
a: (props) => <LocaleLink {...props} lang={lang} />,
}}
/>
</DocsBody>
</DocsPage>
)
}

export function generateStaticParams() {
return source.generateParams()
}

export async function generateMetadata({
params,
}: {
params: Promise<{ lang: string; slug?: string[] }>
}): Promise<Metadata> {
const { lang: rawLang, slug } = await params
const slugs = pageSlug(slug)
const page = source.getPage(slugs, asLang(rawLang))
if (!page) return {}
return {
title: page.data.title,
description: page.data.description,
// Declare the translations as alternates of one article, and name the
// canonical URL, so search engines do not index the English and Chinese
// pages as duplicates of each other.
alternates: docsAlternates(slugs),
}
}
77 changes: 77 additions & 0 deletions apps/docs/app/[lang]/docs-providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"use client"

import Image from "next/image"
import Link from "next/link"
import { useParams, usePathname, useRouter } from "next/navigation"
import { FrameworkProvider, type Framework } from "fumadocs-core/framework"
import { RootProvider } from "fumadocs-ui/provider/base"
import { useCallback, type ReactNode } from "react"
import { i18n, type Lang } from "@/lib/i18n"

const locales = [
{ name: "English", locale: "en" },
{ name: "中文", locale: "zh" },
]

const translations = {
en: {
toc: "On this page",
chooseLanguage: "Choose language",
nextPage: "Next page",
previousPage: "Previous page",
},
zh: {
toc: "本页目录",
chooseLanguage: "选择语言",
nextPage: "下一页",
previousPage: "上一页",
},
} as const

function isLocale(segment: string | undefined): boolean {
return Boolean(segment) && (i18n.languages as readonly string[]).includes(segment as string)
}

function pathForLocale(pathname: string, locale: string) {
const segments = pathname.split("/").filter(Boolean)
// Drop a leading locale segment, whichever language it names — matching on a
// literal "en"/"zh" pair here would silently break when a language is added.
if (isLocale(segments[0])) segments.shift()
const rest = segments.join("/")
if (locale === i18n.defaultLanguage) return rest ? `/${rest}` : "/"
return rest ? `/${locale}/${rest}` : `/${locale}`
}

export function DocsProviders({ lang, children }: { lang: Lang; children: ReactNode }) {
const router = useRouter()
const pathname = pathForLocale(usePathname(), lang)
// Navigation must use the public path during both SSR and hydration.
const usePublicPathname = useCallback(() => pathname, [pathname])

return (
<FrameworkProvider
usePathname={usePublicPathname}
useParams={useParams}
useRouter={useRouter}
Link={Link as Framework["Link"]}
Image={Image as Framework["Image"]}
>
<RootProvider
// The manual ships without site search: Fumadocs' search route needs a
// tokenizer for the Chinese pages, because the default one strips Han
// characters and would return nothing for a Chinese query. Turning the
// toggle on without also adding `app/api/search/route.ts` would give the
// reader a search box that never finds anything.
search={{ enabled: false }}
i18n={{
locale: lang,
locales,
translations: translations[lang],
onLocaleChange: (locale) => router.push(pathForLocale(pathname, locale)),
}}
>
{children}
</RootProvider>
</FrameworkProvider>
)
}
54 changes: 54 additions & 0 deletions apps/docs/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import "../global.css"
import type { Metadata } from "next"
import { notFound } from "next/navigation"
import type { ReactNode } from "react"
import { DocsLayout } from "fumadocs-ui/layouts/docs"
import { baseOptions } from "../layout.config"
import { source } from "@/lib/source"
import { i18n, type Lang } from "@/lib/i18n"
import { DocsProviders } from "./docs-providers"

export const metadata: Metadata = {
title: {
template: "%s | OpenAgentCore Docs",
default: "OpenAgentCore Docs",
},
description: "Documentation for OpenAgentCore.",
}

export function generateStaticParams() {
return i18n.languages.map((lang) => ({ lang }))
}

export default async function LangLayout({
params,
children,
}: {
params: Promise<{ lang: string }>
children: ReactNode
}) {
const { lang: rawLang } = await params
if (!(i18n.languages as readonly string[]).includes(rawLang)) notFound()
const lang = rawLang as Lang

return (
<html lang={lang} suppressHydrationWarning>
{/* Browser extensions may add attributes before React hydrates the body. */}
<body suppressHydrationWarning>
<DocsProviders lang={lang}>
<DocsLayout
tree={source.getPageTree(lang)}
{...baseOptions}
nav={{
...baseOptions.nav,
// The title links to this language's home, not always to English.
url: lang === i18n.defaultLanguage ? "/" : `/${lang}`,
}}
>
{children}
</DocsLayout>
</DocsProviders>
</body>
</html>
)
}
Loading
Loading