diff --git a/amplify.yml b/amplify.yml
new file mode 100644
index 00000000..f4cd1c2e
--- /dev/null
+++ b/amplify.yml
@@ -0,0 +1,61 @@
+version: 1
+frontend:
+ phases:
+ preBuild:
+ commands:
+ - yarn install
+ - yarn docusaurus clean-api-docs all --all-versions
+ - yarn docusaurus gen-api-docs all --all-versions
+ build:
+ commands:
+ - yarn build
+ artifacts:
+ baseDirectory: build
+ files:
+ - "**/*"
+ cache:
+ paths:
+ - node_modules/**/*
+
+ # Explicit rewrite rules so Amplify's SPA fallback never intercepts agent-facing
+ # static files (.md pages, llms-full.txt, skill.md). Rules are evaluated in
+ # order; the SPA catch-all should come last if you ever add one.
+ customRules:
+ - source: "**/*.md"
+ target: "**/*.md"
+ status: "200"
+ - source: "/llms-full.txt"
+ target: "/llms-full.txt"
+ status: "200"
+ - source: "/skill.md"
+ target: "/skill.md"
+ status: "200"
+
+customHeaders:
+ # HTML pages — short CDN TTL so deployments propagate within 1 hour
+ - pattern: "**/*.html"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+
+ # JS / CSS / fonts — content-addressed filenames, safe to cache forever
+ - pattern: "**/assets/**"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=31536000, immutable"
+
+ # Raw Markdown files — short TTL + correct Content-Type for LLM agents
+ - pattern: "**/*.md"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+ - key: Content-Type
+ value: "text/markdown; charset=utf-8"
+
+ # llms.txt and llms-full.txt — short TTL so index updates are visible quickly
+ - pattern: "**/llms*.txt"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+ - key: Content-Type
+ value: "text/plain; charset=utf-8"
diff --git a/cartesi-rollups_versioned_docs/version-1.5/rollups-apis/rollup/cartesi-rollup-http-api.info.mdx b/cartesi-rollups_versioned_docs/version-1.5/rollups-apis/rollup/cartesi-rollup-http-api.info.mdx
index 9ddf37f3..977acdbb 100644
--- a/cartesi-rollups_versioned_docs/version-1.5/rollups-apis/rollup/cartesi-rollup-http-api.info.mdx
+++ b/cartesi-rollups_versioned_docs/version-1.5/rollups-apis/rollup/cartesi-rollup-http-api.info.mdx
@@ -85,7 +85,7 @@ while True:
```
In production mode, if the dApp exits the Rollups initialization script will register a Rollup Exception.
-See [/exception](#api-Default-registerException).
+See [/exception](./register-exception).
In host mode, the Cartesi Rollups infrastructure is not able to detect that the dApp exited.
It is up to the dApp developer to re-launch the dApp.
diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/notices.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/notices.md
index b08181ad..7a90900f 100644
--- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/notices.md
+++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/notices.md
@@ -186,5 +186,5 @@ std::string handle_advance(httplib::Client &cli, picojson::value data)
:::note querying notices
-Frontend clients can query notices using a JSON RPC API exposed by Cartesi Nodes. [Refer to the documentation here](../../development/query-outputs.md#query-all-notices) to query notices from the rollup server.
+Frontend clients can query notices using a JSON RPC API exposed by Cartesi Nodes. [Refer to the documentation here](../../development/query-outputs.md#query-all-notices-and-vouchers) to query notices from the rollup server.
:::
diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md
index a5d13cb0..5503698a 100644
--- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md
+++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md
@@ -467,4 +467,5 @@ Result for getting the node version.
```typescript
interface NodeVersionResult {
data: string; // Semantic version format
-}
\ No newline at end of file
+}
+```
\ No newline at end of file
diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/rollup/cartesi-rollup-http-api.info.mdx b/cartesi-rollups_versioned_docs/version-2.0/api-reference/rollup/cartesi-rollup-http-api.info.mdx
index 9ddf37f3..977acdbb 100644
--- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/rollup/cartesi-rollup-http-api.info.mdx
+++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/rollup/cartesi-rollup-http-api.info.mdx
@@ -85,7 +85,7 @@ while True:
```
In production mode, if the dApp exits the Rollups initialization script will register a Rollup Exception.
-See [/exception](#api-Default-registerException).
+See [/exception](./register-exception).
In host mode, the Cartesi Rollups infrastructure is not able to detect that the dApp exited.
It is up to the dApp developer to re-launch the dApp.
diff --git a/cartesi-rollups_versioned_docs/version-2.0/resources/migration-guide.md b/cartesi-rollups_versioned_docs/version-2.0/resources/migration-guide.md
index 4c5f2704..fdb3ee4a 100644
--- a/cartesi-rollups_versioned_docs/version-2.0/resources/migration-guide.md
+++ b/cartesi-rollups_versioned_docs/version-2.0/resources/migration-guide.md
@@ -9,16 +9,16 @@ Rollups node v2.0 introduces some major changes in how the node works internally
### My back-end...
- handles ERC-20 token deposit inputs. See the [ERC-20 token deposit inputs](#erc-20-token-deposit-inputs) section.
-- handles application address relay inputs. See the [Application address](#application-address) section.
-- generates Ether withdrawal vouchers. See the [Ether withdrawal vouchers](#ether-withdrawal-vouchers) section.
+- handles application address relay inputs. See the Application address section.
+- generates Ether withdrawal vouchers. See the Ether withdrawal vouchers section.
### My front-end...
-- validates notices. See the [Outputs](#outputs) section.
-- executes vouchers. See the [Outputs](#outputs) section.
-- listens to voucher execution events. See the [Outputs](#outputs) section.
-- checks if a voucher was executed. See the [Outputs](#outputs) section.
-- uses inspect calls. See the [Inspect calls](#inspect-calls) section.
-- uses JSON-RPC queries. See the [JSON queries](#jsonrpc-queries) section.
+- validates notices. See the Outputs section.
+- executes vouchers. See the Outputs section.
+- listens to voucher execution events. See the Outputs section.
+- checks if a voucher was executed. See the Outputs section.
+- uses inspect calls. See the Inspect calls section.
+- uses JSON-RPC queries. See the JSON queries section.
:::note
If your application uses a high-level framework(ex. Deroll, Rollmelette etc.) for either backend or frontend, check if the framework has already implemented the changes described in this guide.
diff --git a/cartesi-rollups_versioned_docs/version-2.0/tutorials/calculator.md b/cartesi-rollups_versioned_docs/version-2.0/tutorials/calculator.md
index fc8faff3..6927dac7 100644
--- a/cartesi-rollups_versioned_docs/version-2.0/tutorials/calculator.md
+++ b/cartesi-rollups_versioned_docs/version-2.0/tutorials/calculator.md
@@ -342,7 +342,7 @@ for (const output of outputs) {
}
```
-You can also [query a notice based on its input index](../development/query-outputs.md#query-a-single-notice).
+You can also [query a notice based on its input index](../development/query-outputs.md#query-a-single-notice-or-voucher).
Congratulations, you have successfully built a dApp on Cartesi Rollups!
diff --git a/customHttp.yml b/customHttp.yml
new file mode 100644
index 00000000..0c87d593
--- /dev/null
+++ b/customHttp.yml
@@ -0,0 +1,28 @@
+customHeaders:
+ # Hashed assets (JS, CSS, images) — content-addressed filenames, safe to cache forever
+ - pattern: "**/assets/**"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=31536000, immutable"
+
+ # HTML pages — short CDN TTL so deployments propagate quickly
+ - pattern: "**/*.html"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+
+ # Raw Markdown files — short TTL + correct MIME type for LLM agents
+ - pattern: "**/*.md"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+ - key: Content-Type
+ value: "text/markdown; charset=utf-8"
+
+ # llms.txt and llms-full.txt — short TTL so index updates are visible quickly
+ - pattern: "**/llms*.txt"
+ headers:
+ - key: Cache-Control
+ value: "public, max-age=0, s-maxage=3500, must-revalidate"
+ - key: Content-Type
+ value: "text/plain; charset=utf-8"
diff --git a/docs/cartesi-machine/host/cmdline.md b/docs/cartesi-machine/host/cmdline.md
index 26cc9f1c..e6466cc8 100644
--- a/docs/cartesi-machine/host/cmdline.md
+++ b/docs/cartesi-machine/host/cmdline.md
@@ -564,7 +564,7 @@ d8b96e5b7f6f459e9cb6a2f41bf276c7b85c10cd4662c04cbbb365434726c0a0
```
As expected, the hash values match.
-The `sibling_hashes` array contains the hashes of the siblings to all nodes in the path from the root all the way down to the target node (excluding the root, which has no sibling).
+The `sibling_hashes` array contains the hashes of the siblings to all nodes in the path from the root all the way down to the target node (excluding the root, which has no sibling).
In a process explained in the [blockchain perspective](../blockchain/hash.md), using the `address` field, the `target_hash` hash, and the `sibling_hashes` array, it is possible to go up the tree computing the hashes along the path, until the root hash is produced.
If the root hash obtained by this process matches the expected root hash, the proof is valid.
Otherwise, something is amiss.
diff --git a/docs/cartesi-machine/host/lua.md b/docs/cartesi-machine/host/lua.md
index 24c2b06d..2c80e4fc 100644
--- a/docs/cartesi-machine/host/lua.md
+++ b/docs/cartesi-machine/host/lua.md
@@ -494,7 +494,7 @@ Note that the `machine:run()` method can return precociously for a variety of re
The `iflags` CSR contains a bit `H` that is set to true whenever the machine is halted, and a bit `Y` that is set to true whenever the machine has yielded manual.
The `machine:read_iflags_H()` and `machine:read_iflags_Y()` methods return the value of these bits, respectively, and the loop breaks if any of them is set.
-
+
For example, to run the configuration stored in `./config/cat-foo-bar.lua` (assuming `./foo.ext2` is available) simply run
diff --git a/docs/cartesi-machine/target/architecture.md b/docs/cartesi-machine/target/architecture.md
index 22926d58..98926c4a 100644
--- a/docs/cartesi-machine/target/architecture.md
+++ b/docs/cartesi-machine/target/architecture.md
@@ -573,7 +573,7 @@ When an application identifies an inspect-state request, it obtains the query fr
While processing inspect-state requests, the application can emit vouchers, or exceptions.
It writes data for all these to the Rollup TX buffer memory range and sends the appropriate command to the HTIF yield device.
-The format for all these request and response data are as follows:
+The format for all these request and response data are as follows:
diff --git a/docs/tutorials/gpg-verify/larger-files.md b/docs/tutorials/gpg-verify/larger-files.md
index 17bf7408..eacff598 100644
--- a/docs/tutorials/gpg-verify/larger-files.md
+++ b/docs/tutorials/gpg-verify/larger-files.md
@@ -12,7 +12,7 @@ title: Processing larger files
As discussed in the [documentation](/compute/logger_drive), Cartesi Compute provides a _Logger service_ that is capable of publishing and retrieving data more efficiently to and from the blockchain. More specifically, this service stores the information as _call data_ and allows it to be split into smaller chunks, thus enabling storage of data that is larger than a single block's limit. Although not suitable for direct usage within smart contracts themselves, this strategy is perfect for passing along on-chain data _references_ to off-chain components, which can then download it from the blockchain for processing.
-On top of the Logger service, Cartesi Compute also features integrated IPFS support in its nodes. As also explained in the [documentation](/compute/logger_drive/#ipfs-integrated-support), generally speaking IPFS alone is not sufficient to ensure data availability for verifying a computation, since it cannot guarantee that the validator nodes will be able to access the data when needed. However, in Cartesi Compute it is possible to upload the data to IPFS, and then trigger the Logger service automatically as a fallback should any node fail to retrieve it. As such, for the vast majority of cases in which actors do not misbehave, and for specific scenarios for which IPFS data availability is not an issue, using IPFS can prevent data from ever having to be published to the blockchain, with obvious benefits in terms of cost and performance.
+On top of the Logger service, Cartesi Compute also features integrated IPFS support in its nodes. As also explained in the [documentation](/compute/logger_drive/#integrated-ipfs-support), generally speaking IPFS alone is not sufficient to ensure data availability for verifying a computation, since it cannot guarantee that the validator nodes will be able to access the data when needed. However, in Cartesi Compute it is possible to upload the data to IPFS, and then trigger the Logger service automatically as a fallback should any node fail to retrieve it. As such, for the vast majority of cases in which actors do not misbehave, and for specific scenarios for which IPFS data availability is not an issue, using IPFS can prevent data from ever having to be published to the blockchain, with obvious benefits in terms of cost and performance.
In this context, we will now build upon our [previous dApp implementation](../gpg-verify/full-dapp.md) and add a method that uses the Logger and IPFS services to allow a larger file's signature to be verified using Cartesi Compute.
diff --git a/plugins/serve-markdown.js b/plugins/serve-markdown.js
index c29f6390..7917eb01 100644
--- a/plugins/serve-markdown.js
+++ b/plugins/serve-markdown.js
@@ -122,14 +122,7 @@ function toPermalink(reqPath, wantsMarkdown) {
*/
function injectLlmsDirective(content, siteUrl) {
const directive = `> For the complete documentation index, see [llms.txt](${siteUrl}/llms.txt)`;
- // If the file starts with YAML frontmatter, insert after the closing ---
- if (content.startsWith('---')) {
- const end = content.indexOf('\n---', 3);
- if (end !== -1) {
- const afterFrontmatter = end + 4; // past the closing ---
- return content.slice(0, afterFrontmatter) + '\n\n' + directive + '\n' + content.slice(afterFrontmatter);
- }
- }
+ // Always prepend at the very top, before any YAML frontmatter.
return directive + '\n\n' + content;
}
@@ -166,65 +159,102 @@ const SECTION_ALIASES = new Map([
* @returns {import('express').RequestHandler}
*/
function makeMarkdownHandler(urlMap, siteDir, siteUrl) {
- return function markdownHandler(req, res, next) {
- const wantsMarkdown = (req.headers['accept'] ?? '').includes('text/markdown');
- const permalink = toPermalink(req.path, wantsMarkdown);
- if (!permalink) return next();
-
- // Permalinks in LLMS_INDEX_ROUTES serve llms.txt (with host rewriting)
- // so agents get a navigation index rather than a single page.
- if (LLMS_INDEX_ROUTES.has(permalink)) {
- try {
- let content = fs.readFileSync(path.join(siteDir, 'static', 'llms.txt'), 'utf8');
- const reqOrigin = `${req.protocol}://${req.headers['host']}`;
- if (reqOrigin && reqOrigin !== siteUrl) {
- content = content.split(siteUrl).join(reqOrigin);
+ return async function markdownHandler(req, res, next) {
+ try {
+ const wantsMarkdown = (req.headers['accept'] ?? '').includes('text/markdown');
+ const permalink = toPermalink(req.path, wantsMarkdown);
+ if (!permalink) return next();
+
+ const reqOrigin = `${req.protocol}://${req.headers['host']}`;
+
+ // Permalinks in LLMS_INDEX_ROUTES serve llms.txt (with host rewriting)
+ // so agents get a navigation index rather than a single page.
+ if (LLMS_INDEX_ROUTES.has(permalink)) {
+ try {
+ let content = fs.readFileSync(path.join(siteDir, 'static', 'llms.txt'), 'utf8');
+ if (reqOrigin && reqOrigin !== siteUrl) {
+ content = content.split(siteUrl).join(reqOrigin);
+ }
+ res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
+ res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
+ res.setHeader('X-Content-Type-Options', 'nosniff');
+ return res.send(content);
+ } catch {
+ return next();
}
- res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
- res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
- res.setHeader('X-Content-Type-Options', 'nosniff');
- return res.send(content);
- } catch {
+ }
+
+ // Virtual aliases: resolve to the source file of another permalink.
+ const aliasTarget = SECTION_ALIASES.get(permalink);
+ const sourceFile = aliasTarget
+ ? urlMap.get(aliasTarget)
+ : urlMap.get(permalink);
+
+ if (!sourceFile) {
+ // Generated-index fallback: the page has no markdown source but
+ // Docusaurus builds an HTML page for it (e.g. sidebar categories with
+ // link: { type: 'generated-index' }). Fetch the HTML from the dev
+ // server itself, extract the , and return a minimal .md file.
+ // Node.js 20 built-in fetch is used — no extra dependency needed.
+ try {
+ const htmlRes = await fetch(`${reqOrigin}${permalink}`);
+ if (htmlRes.ok) {
+ const html = await htmlRes.text();
+ const titleMatch = html.match(/([^|<]+)/);
+ const title = titleMatch ? titleMatch[1].trim() : permalink;
+ const content = injectLlmsDirective(`# ${title}\n`, reqOrigin || siteUrl);
+ res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
+ res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
+ res.setHeader('X-Content-Type-Options', 'nosniff');
+ return res.send(content);
+ }
+ } catch { /* fall through to next() */ }
return next();
}
- }
- // Virtual aliases: resolve to the source file of another permalink.
- const aliasTarget = SECTION_ALIASES.get(permalink);
- const sourceFile = aliasTarget
- ? urlMap.get(aliasTarget)
- : urlMap.get(permalink);
+ let content;
+ try {
+ content = fs.readFileSync(sourceFile, 'utf8');
+ } catch {
+ return next();
+ }
- if (!sourceFile) return next();
+ content = injectLlmsDirective(content, reqOrigin || siteUrl);
- let content;
- try {
- content = fs.readFileSync(sourceFile, 'utf8');
- } catch {
- return next();
+ res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
+ res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
+ res.setHeader('X-Content-Type-Options', 'nosniff');
+ return res.send(content);
+ } catch (err) {
+ next(err);
}
-
- const reqOrigin = `${req.protocol}://${req.headers['host']}`;
- content = injectLlmsDirective(content, reqOrigin || siteUrl);
-
- res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
- res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
- res.setHeader('X-Content-Type-Options', 'nosniff');
- return res.send(content);
};
}
/**
* Concatenate all documentation pages into a single string for llms-full.txt.
* Pages are sorted by permalink for consistent ordering.
- * Each page is preceded by a URL header so LLMs can anchor content to its source.
+ * Each page is preceded by a comment so LLMs can anchor content to its source.
+ *
+ * The file starts with the llms.txt header so it has the mandatory H1 heading
+ * required by the llmstxt.org specification and expected by agent checkers.
*
* @param {Map} urlMap
* @param {string} siteUrl e.g. "https://docs.cartesi.io"
+ * @param {string} siteDir absolute path to the Docusaurus site directory
* @returns {string}
*/
-function buildLlmsFullContent(urlMap, siteUrl) {
+function buildLlmsFullContent(urlMap, siteUrl, siteDir) {
const parts = [];
+
+ // Prepend the llms.txt header — provides the required H1 heading and index preamble.
+ try {
+ const llmsHeader = fs.readFileSync(path.join(siteDir, 'static', 'llms.txt'), 'utf8');
+ parts.push(llmsHeader.trim());
+ } catch {
+ parts.push('# Cartesi Documentation\n\n> Full documentation snapshot for AI agents.');
+ }
+
const sortedEntries = [...urlMap.entries()].sort(([a], [b]) => a.localeCompare(b));
for (const [permalink, sourcePath] of sortedEntries) {
@@ -235,7 +265,7 @@ function buildLlmsFullContent(urlMap, siteUrl) {
continue;
}
const pageUrl = siteUrl.replace(/\/$/, '') + permalink;
- parts.push(`\n\n---\n\nSource: ${pageUrl}\n\n${content.trim()}`);
+ parts.push(`\n\n---\n\n\n\n${content.trim()}`);
}
return parts.join('');
@@ -282,13 +312,14 @@ function makeLlmsTxtHandler(siteDir, siteUrl) {
*
* @param {Map} urlMap
* @param {string} siteUrl
+ * @param {string} siteDir
* @returns {import('express').RequestHandler}
*/
-function makeLlmsFullHandler(urlMap, siteUrl) {
+function makeLlmsFullHandler(urlMap, siteUrl, siteDir) {
return function llmsFullHandler(req, res, next) {
if (req.path !== '/llms-full.txt') return next();
- const content = buildLlmsFullContent(urlMap, siteUrl);
+ const content = buildLlmsFullContent(urlMap, siteUrl, siteDir);
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
res.setHeader('X-Content-Type-Options', 'nosniff');
@@ -306,7 +337,11 @@ function makeLlmsFullHandler(urlMap, siteUrl) {
*/
module.exports = function serveMarkdownPlugin(context) {
const { siteDir, siteConfig } = context;
- const siteUrl = siteConfig.url || 'https://docs.cartesi.io';
+ // Derive the site URL from DOCS_DOMAIN (the same variable used by the CDK
+ // stack for the CloudFront custom domain) so only one variable needs to be
+ // set per branch in Amplify Console.
+ // Defaults to staging so unset branches get correct staging URLs.
+ const siteUrl = `https://${process.env.DOCS_DOMAIN ?? 'staging.docs.cartesi.io'}`;
// Shared mutable map populated in allContentLoaded and consumed in
// configureWebpack + postBuild. allContentLoaded always runs before both.
@@ -315,6 +350,35 @@ module.exports = function serveMarkdownPlugin(context) {
return {
name: 'docusaurus-plugin-serve-markdown',
+ // ── 0. Inject a hidden in-body element linking to /llms.txt ─────────────
+ //
+ // AFDocs and similar agent-readiness checkers look for an in-body element
+ // that references /llms.txt so agents fetching the HTML version of a page
+ // can discover the documentation index. The element is visually hidden
+ // (clipped off-screen) so it does not affect the page layout, but it
+ // survives HTML-to-markdown conversion and is visible to DOM parsers.
+ //
+ // preBodyTags are inserted as the very first element inside , which
+ // ensures the directive appears well within the first 50% of the page.
+ //
+ injectHtmlTags() {
+ return {
+ preBodyTags: [
+ {
+ tagName: 'div',
+ attributes: {
+ style:
+ 'position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;',
+ },
+ innerHTML:
+ 'AI agent documentation index: llms.txt.' +
+ ' Raw markdown for any page is available by appending .md to the URL.' +
+ ' Full content snapshot: llms-full.txt.',
+ },
+ ],
+ };
+ },
+
// ── 1. Build URL → source file map (Docusaurus v3 hook) ─────────────────
//
// In Docusaurus v3, allContent is available only in allContentLoaded, not
@@ -326,6 +390,16 @@ module.exports = function serveMarkdownPlugin(context) {
for (const [permalink, absPath] of discovered) {
urlMap.set(permalink, absPath);
}
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const logger = require('@docusaurus/logger').default;
+ if (urlMap.size === 0) {
+ logger.warn(
+ '[serve-markdown] No docs discovered in allContent — .md files and llms-full.txt will NOT be generated. ' +
+ 'Check that @docusaurus/plugin-content-docs instances are correctly configured.',
+ );
+ } else {
+ logger.info(`[serve-markdown] Discovered ${urlMap.size} pages for .md generation.`);
+ }
},
// ── 2. Dev server: intercept .md / Accept:text/markdown requests ─────────
@@ -343,7 +417,7 @@ module.exports = function serveMarkdownPlugin(context) {
if (isServer) return {};
const markdownHandler = makeMarkdownHandler(urlMap, siteDir, siteUrl);
- const llmsFullHandler = makeLlmsFullHandler(urlMap, siteUrl);
+ const llmsFullHandler = makeLlmsFullHandler(urlMap, siteUrl, siteDir);
const llmsTxtHandler = makeLlmsTxtHandler(siteDir, siteUrl);
return {
@@ -366,6 +440,21 @@ module.exports = function serveMarkdownPlugin(context) {
let written = 0;
let skipped = 0;
+ // Build the rewritten llms.txt content once.
+ // static/llms.txt always contains the production domain; when siteUrl
+ // differs (e.g. staging) every internal link is substituted so agents
+ // following links from llms.txt land on the correct environment.
+ const llmsTxtRaw = fs.readFileSync(path.join(siteDir, 'static', 'llms.txt'), 'utf8');
+ const llmsTxtContent = llmsTxtRaw.replaceAll('https://docs.cartesi.io', siteUrl);
+
+ // Overwrite the llms.txt that Docusaurus copied from static/ so the
+ // served file also has the correct URLs.
+ try {
+ fs.writeFileSync(path.join(outDir, 'llms.txt'), llmsTxtContent, 'utf8');
+ } catch {
+ // Non-fatal
+ }
+
// Write individual .md files next to HTML pages
for (const [permalink, sourcePath] of urlMap.entries()) {
// /some/page/ → outDir/some/page.md
@@ -378,10 +467,9 @@ module.exports = function serveMarkdownPlugin(context) {
try {
fs.mkdirSync(outputDir, { recursive: true });
- // LLMS_INDEX_ROUTES: write llms.txt content instead of the page.
+ // LLMS_INDEX_ROUTES: write the rewritten llms.txt instead of the page.
if (LLMS_INDEX_ROUTES.has(permalink)) {
- const llmsTxt = fs.readFileSync(path.join(siteDir, 'static', 'llms.txt'), 'utf8');
- fs.writeFileSync(mdOutputPath, llmsTxt, 'utf8');
+ fs.writeFileSync(mdOutputPath, llmsTxtContent, 'utf8');
written++;
continue;
}
@@ -410,9 +498,62 @@ module.exports = function serveMarkdownPlugin(context) {
}
}
- // Write llms-full.txt — all documentation concatenated
+ // Write .md files for generated-index pages.
+ //
+ // Docusaurus generates HTML pages for sidebar categories that use
+ // link: { type: 'generated-index' } — e.g. /new-to-cartesi/, /earn-ctsi/,
+ // /compute/tutorials/calculator/. These pages appear in the sitemap but
+ // have no markdown source file, so the urlMap loop above skips them and
+ // they produce a 404 when requested with the .md extension.
+ //
+ // Fix: walk outDir after the main loop and write a minimal .md file for
+ // every directory that has an index.html but no sibling .md file yet.
+ // The title is extracted from the tag in index.html.
+ //
+ // Directories that are not documentation pages are skipped.
+ const SKIP_DIRS = new Set(['assets', 'img', '.well-known', 'search']);
+
+ function generateIndexMd(dir) {
+ let count = 0;
+ let entries;
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return count; }
+
+ for (const entry of entries) {
+ if (!entry.isDirectory() || SKIP_DIRS.has(entry.name)) continue;
+ const subDir = path.join(dir, entry.name);
+ const indexHtml = path.join(subDir, 'index.html');
+ if (!fs.existsSync(indexHtml)) { count += generateIndexMd(subDir); continue; }
+
+ // Derive the sibling .md path: outDir/some/section.md
+ const relDir = path.relative(outDir, subDir);
+ const mdPath = path.join(outDir, relDir + '.md');
+
+ if (!fs.existsSync(mdPath)) {
+ try {
+ const html = fs.readFileSync(indexHtml, 'utf8');
+ // Extract just the page title (before the " | Site Name" suffix).
+ const titleMatch = html.match(/([^|<]+)/);
+ const title = titleMatch ? titleMatch[1].trim() : relDir;
+ const content = injectLlmsDirective(`# ${title}\n`, siteUrl);
+ fs.mkdirSync(path.dirname(mdPath), { recursive: true });
+ fs.writeFileSync(mdPath, content, 'utf8');
+ count++;
+ } catch { /* non-fatal */ }
+ }
+
+ count += generateIndexMd(subDir);
+ }
+ return count;
+ }
+
+ const generatedIndexCount = generateIndexMd(outDir);
+
+ // Write llms-full.txt — all documentation concatenated.
+ // buildLlmsFullContent uses siteUrl for page URLs but reads the static
+ // llms.txt header from disk; replaceAll fixes the header section too.
try {
- const llmsFullContent = buildLlmsFullContent(urlMap, siteUrl);
+ const llmsFullContent = buildLlmsFullContent(urlMap, siteUrl, siteDir)
+ .replaceAll('https://docs.cartesi.io', siteUrl);
fs.writeFileSync(path.join(outDir, 'llms-full.txt'), llmsFullContent, 'utf8');
} catch {
// Non-fatal: llms-full.txt is a convenience file
@@ -422,7 +563,7 @@ module.exports = function serveMarkdownPlugin(context) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const logger = require('@docusaurus/logger').default;
logger.info(
- `[serve-markdown] wrote ${written} .md files and llms-full.txt to build output` +
+ `[serve-markdown] wrote ${written} .md files, ${generatedIndexCount} index .md files, and llms-full.txt to build output` +
(skipped ? ` (${skipped} skipped)` : ''),
);
},
diff --git a/static/llms.txt b/static/llms.txt
index 7ff53a37..c4bb4310 100644
--- a/static/llms.txt
+++ b/static/llms.txt
@@ -4,11 +4,11 @@
## Instructions for AI Agents
-Use this file to discover and navigate Cartesi's documentation. Each link below points directly to the raw Markdown source for that page. A complete machine-readable copy of all docs concatenated is available at [https://docs.cartesi.io/llms-full.txt](https://docs.cartesi.io/llms-full.txt).
+Use this file to discover and navigate Cartesi's documentation. Each link below points directly to the raw Markdown source for that page. A complete machine-readable copy of all docs concatenated is available at [https://docs.cartesi.io/llms-full.txt](https://docs.cartesi.io/llms-full.txt). An agent skill definition (operating guidance for AI assistants) is at [https://docs.cartesi.io/skill.md](https://docs.cartesi.io/skill.md).
### Version priority
-**Always default to Cartesi Rollups v2.0** (`/cartesi-rollups/2.0/`) when answering any question about building, deploying, or interacting with Cartesi applications. v2.0 is the current production version. v1.5 pages exist in the sitemap but are intentionally excluded from this index because v1.5 is superseded — its APIs, CLI commands, deployment model, and node architecture differ significantly from v2.0. Do not surface v1.5 content unless the user explicitly asks about v1.5.
+**Always default to Cartesi Rollups v2.0** when answering any question about building, deploying, or interacting with Cartesi applications. v2.0 is the current production version. v1.5 is deprecated and included at the bottom of this index for reference only — do not surface v1.5 content unless the user explicitly asks about v1.5, since its APIs, CLI commands, deployment model, and node architecture differ significantly from v2.0.
### Documentation map
@@ -44,8 +44,8 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C
## New to Cartesi
-- [New to Cartesi](https://docs.cartesi.io/new-to-cartesi/overview.md): Introduction for newcomers
-- [Cartesi Overview](https://docs.cartesi.io/new-to-cartesi/overview.md): What is Cartesi
+- [New to Cartesi](https://docs.cartesi.io/new-to-cartesi.md): Section index for newcomers to Cartesi
+- [New to Cartesi](https://docs.cartesi.io/new-to-cartesi/overview.md): What Cartesi is and an introduction for newcomers
- [Scalability](https://docs.cartesi.io/new-to-cartesi/scalability.md): How Cartesi addresses blockchain scalability
- [Choose your Onboarding Path](https://docs.cartesi.io/new-to-cartesi/onboarding.md): Guided onboarding paths for different profiles
@@ -74,6 +74,7 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C
## Cartesi Rollups v2.0 — Getting Started
+- [Cartesi Rollups v2.0](https://docs.cartesi.io/cartesi-rollups/2.0.md): Section root for Cartesi Rollups v2.0
- [Overview](https://docs.cartesi.io/cartesi-rollups/overview.md): Cartesi Rollups v2.0 introduction
- [Architecture](https://docs.cartesi.io/cartesi-rollups/2.0/getting-started/architecture.md): On-chain and off-chain components
- [Concepts](https://docs.cartesi.io/cartesi-rollups/2.0/getting-started/concepts.md): Key concepts and terminology
@@ -193,6 +194,13 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C
- [Self-hosted deployment](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/self-hosted.md): Run your own node
- [Public snapshot](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/snapshot.md): Machine state management
+## Cartesi Rollups v2.0 — Build with AI
+
+- [Overview](https://docs.cartesi.io/cartesi-rollups/2.0/build-with-ai/overview.md): Using AI assistants and agents to build Cartesi applications
+- [MCP Server](https://docs.cartesi.io/cartesi-rollups/2.0/build-with-ai/mcp-server.md): Cartesi MCP server for AI-assisted development
+- [Skills](https://docs.cartesi.io/cartesi-rollups/2.0/build-with-ai/skills.md): Agent skills for Cartesi development workflows
+- [Prompting](https://docs.cartesi.io/cartesi-rollups/2.0/build-with-ai/prompting.md): Effective prompting patterns for Cartesi development
+
## Cartesi Rollups v2.0 — Tutorials
- [Counter](https://docs.cartesi.io/cartesi-rollups/2.0/tutorials/counter.md): Build a counter application
@@ -269,7 +277,13 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C
- [Wallets](https://docs.cartesi.io/compute/wallet.md): Wallet integration
- [Putting Things Together](https://docs.cartesi.io/compute/workflow.md): End-to-end workflow
- [On-chain API](https://docs.cartesi.io/compute/api.md): On-chain API reference
-- [References](https://docs.cartesi.io/compute/references/): Reference documentation
+- [References](https://docs.cartesi.io/compute/references.md): Reference documentation
+- [Tutorials](https://docs.cartesi.io/compute/tutorials.md): Cartesi Compute tutorial index
+- [Hello World tutorial](https://docs.cartesi.io/compute/tutorials/helloworld.md): Hello World Cartesi Compute tutorial
+- [Calculator tutorial](https://docs.cartesi.io/compute/tutorials/calculator.md): Calculator Cartesi Compute tutorial
+- [Dogecoin Hash tutorial](https://docs.cartesi.io/compute/tutorials/dogecoin-hash.md): Dogecoin Hash Cartesi Compute tutorial
+- [Generic Script tutorial](https://docs.cartesi.io/compute/tutorials/generic-script.md): Generic Script Cartesi Compute tutorial
+- [GPG Verify tutorial](https://docs.cartesi.io/compute/tutorials/gpg-verify.md): GPG Verify Cartesi Compute tutorial
## Legacy Tutorials (Cartesi Compute SDK)
@@ -315,7 +329,142 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C
## Earn CTSI
+- [Earn CTSI](https://docs.cartesi.io/earn-ctsi.md): Section index for staking and earning CTSI
- [Staking overview](https://docs.cartesi.io/earn-ctsi/staking.md): Staking and earning CTSI overview
- [Create a public pool](https://docs.cartesi.io/earn-ctsi/public-pool.md): Create and manage a staking pool
- [Run a private node](https://docs.cartesi.io/earn-ctsi/run-node.md): Run a Cartesi node privately
- [FAQs](https://docs.cartesi.io/earn-ctsi/staking-faq.md): Staking frequently asked questions
+
+## Cartesi Rollups v1.5 (Deprecated)
+
+> **Deprecated.** Cartesi Rollups v1.5 is superseded by v2.0. APIs, CLI commands, deployment model, and node architecture differ significantly from v2.0. Always prefer v2.0 documentation unless the user explicitly asks about v1.5.
+
+### v1.5 — Getting Started
+
+- [Overview](https://docs.cartesi.io/cartesi-rollups/1.5.md): Cartesi Rollups v1.5 section root
+- [Quickstart](https://docs.cartesi.io/cartesi-rollups/1.5/quickstart.md): Build and run your first Cartesi Rollups v1.5 application
+- [Schema Documentation](https://docs.cartesi.io/cartesi-rollups/1.5/api/graphql.md): Full GraphQL schema reference (auto-generated)
+
+### v1.5 — Core Concepts
+
+- [Architecture](https://docs.cartesi.io/cartesi-rollups/1.5/core-concepts/architecture.md): On-chain and off-chain components
+- [Cartesi Machine](https://docs.cartesi.io/cartesi-rollups/1.5/core-concepts/cartesi-machine.md): Cartesi Machine in the v1.5 rollups context
+- [Mainnet considerations](https://docs.cartesi.io/cartesi-rollups/1.5/core-concepts/mainnet-considerations.md): Production deployment considerations
+- [Optimistic Rollups](https://docs.cartesi.io/cartesi-rollups/1.5/core-concepts/optimistic-rollups.md): How optimistic rollups work
+
+### v1.5 — Development
+
+- [Installation](https://docs.cartesi.io/cartesi-rollups/1.5/development/installation.md): Install v1.5 development tools
+- [Creating an application](https://docs.cartesi.io/cartesi-rollups/1.5/development/creating-application.md): Bootstrap a new v1.5 Cartesi dApp
+- [Building the application](https://docs.cartesi.io/cartesi-rollups/1.5/development/building-the-application.md): Build your application for v1.5
+- [Running the application](https://docs.cartesi.io/cartesi-rollups/1.5/development/running-the-application.md): Run and test locally with v1.5
+- [Send requests](https://docs.cartesi.io/cartesi-rollups/1.5/development/send-requests.md): Send inputs to your v1.5 dApp
+- [Retrieve outputs](https://docs.cartesi.io/cartesi-rollups/1.5/development/retrieve-outputs.md): Query outputs from your v1.5 dApp
+- [Asset handling](https://docs.cartesi.io/cartesi-rollups/1.5/development/asset-handling.md): Deposits and withdrawals in v1.5
+- [CLI commands](https://docs.cartesi.io/cartesi-rollups/1.5/development/cli-commands.md): Cartesi CLI v1.x reference
+- [Migration guide](https://docs.cartesi.io/cartesi-rollups/1.5/development/migration.md): Migrate from older versions to v1.5
+
+### v1.5 — Deployment
+
+- [Introduction](https://docs.cartesi.io/cartesi-rollups/1.5/deployment/introduction.md): Overview of v1.5 deployment options
+- [Self-hosted deployment](https://docs.cartesi.io/cartesi-rollups/1.5/deployment/self-hosted.md): Run your own v1.5 node
+
+### v1.5 — External Resources
+
+- [Community tools](https://docs.cartesi.io/cartesi-rollups/1.5/external-resources/community-tools.md): Third-party tools and integrations for v1.5
+- [Integration guides](https://docs.cartesi.io/cartesi-rollups/1.5/external-resources/integration-guides.md): Integration examples for v1.5
+
+### v1.5 — APIs Overview
+
+- [Rollups APIs](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis.md): API overview for Cartesi Rollups v1.5
+
+### v1.5 — Backend API
+
+- [Introduction](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/backend/introduction.md): Backend HTTP API overview
+- [Notices](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/backend/notices.md): Informational statements
+- [Vouchers](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/backend/vouchers.md): Executable actions on base layer
+- [Reports](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/backend/reports.md): Application logs
+
+### v1.5 — Rollup HTTP API
+
+- [Cartesi Rollup HTTP API](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/cartesi-rollup-http-api.md): HTTP API specification (auto-generated)
+- [Add Voucher](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/add-voucher.md): Emit a voucher from the backend
+- [Add Notice](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/add-notice.md): Emit a notice from the backend
+- [Add Report](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/add-report.md): Emit a report from the backend
+- [Finish](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/finish.md): Complete input processing
+- [Register Exception](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/rollup/register-exception.md): Register an exception
+
+### v1.5 — Inspect API
+
+- [Inspect State (spec)](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/inspect/inspect-state-http-api-for-cartesi-rollups.md): Inspect HTTP API specification (auto-generated)
+- [Inspect](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/inspect/inspect.md): Query application state
+
+### v1.5 — GraphQL API
+
+- [Overview](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/overview.md): GraphQL API overview
+- [InputFilter](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/inputs/input-filter.md): Input filter type
+- [CompletionStatus](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/completion-status.md): Completion status enum
+- [InputConnection](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/input-connection.md): Input pagination connection
+- [InputEdge](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/input-edge.md): Input connection edge
+- [Input](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/input.md): Input object type
+- [NoticeConnection](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/notice-connection.md): Notice pagination connection
+- [NoticeEdge](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/notice-edge.md): Notice connection edge
+- [Notice](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/notice.md): Notice object type
+- [OutputValidityProof](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/output-validity-proof.md): Output validity proof type
+- [PageInfo](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/page-info.md): Pagination info type
+- [Proof](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/proof.md): Proof object type
+- [ReportConnection](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/report-connection.md): Report pagination connection
+- [ReportEdge](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/report-edge.md): Report connection edge
+- [Report](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/report.md): Report object type
+- [VoucherConnection](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/voucher-connection.md): Voucher pagination connection
+- [VoucherEdge](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/voucher-edge.md): Voucher connection edge
+- [Voucher](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/objects/voucher.md): Voucher object type
+- [Inputs query](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/queries/inputs.md): Query inputs via GraphQL
+- [Notices query](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/queries/notices.md): Query notices via GraphQL
+- [Reports query](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/queries/reports.md): Query reports via GraphQL
+- [Vouchers query](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/queries/vouchers.md): Query vouchers via GraphQL
+- [BigInt](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/scalars/big-int.md): BigInt scalar type
+- [Boolean](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/scalars/boolean.md): Boolean scalar type
+- [DateTime](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/scalars/date-time.md): DateTime scalar type
+- [Int](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/scalars/int.md): Int scalar type
+- [String](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/scalars/string.md): String scalar type
+
+### v1.5 — GraphQL Directives
+
+- [deprecated](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/directives/deprecated.md): Deprecated directive
+- [include](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/directives/include.md): Include directive
+- [skip](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/directives/skip.md): Skip directive
+- [specifiedBy](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/graphql/directives/specified-by.md): SpecifiedBy directive
+
+### v1.5 — JSON-RPC API
+
+- [JSON-RPC Overview](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/overview.md): Contract API overview
+- [CartesiDApp](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/application.md): Per-dApp contract ABI
+- [CartesiDAppFactory](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/application-factory.md): Deploy CartesiDApp contracts
+- [InputBox](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/input-box.md): Entry point for user inputs
+- [EtherPortal](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/portals/EtherPortal.md): ETH deposits
+- [ERC20Portal](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/portals/ERC20Portal.md): ERC-20 token deposits
+- [ERC721Portal](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/portals/ERC721Portal.md): NFT deposits
+- [ERC1155SinglePortal](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/portals/ERC1155SinglePortal.md): ERC-1155 single token deposits
+- [ERC1155BatchPortal](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/portals/ERC1155BatchPortal.md): ERC-1155 batch deposits
+- [DAppAddressRelay](https://docs.cartesi.io/cartesi-rollups/1.5/rollups-apis/json-rpc/relays/relays.md): Relay contract ABI
+
+### v1.5 — Tutorials
+
+- [Counter](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/counter.md): Build a counter application
+- [Calculator](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/calculator.md): Build a calculator application
+- [Ether Wallet](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/ether-wallet.md): Integrating Ether wallet functionality
+- [ERC-20 Wallet](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/erc-20-token-wallet.md): Integrating ERC20 token wallet functionality
+- [ERC-721 Wallet](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/erc-721-token-wallet.md): Integrating ERC721 token wallet functionality
+- [Marketplace](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/marketplace.md): Build a marketplace application
+- [React Frontend](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/react-frontend-application.md): Build a React frontend for Cartesi v1.5 apps
+- [CLI Account Abstraction](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/cli-account-abstraction-feauture.md): Sponsored transactions via CLI account abstraction
+
+### v1.5 — Tutorial Snippets
+
+- [Counter (JavaScript)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/counter-js.md): Counter application JavaScript snippet
+- [Counter (Python)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/counter-py.md): Counter application Python snippet
+- [Counter (Rust)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/counter-rs.md): Counter application Rust snippet
+- [Marketplace (JavaScript)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/marketplace-js.md): Marketplace application JavaScript snippet
+- [Marketplace (Python)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/marketplace-py.md): Marketplace application Python snippet
+- [Marketplace (Rust)](https://docs.cartesi.io/cartesi-rollups/1.5/tutorials/snippets/marketplace-rs.md): Marketplace application Rust snippet
diff --git a/static/skill.md b/static/skill.md
new file mode 100644
index 00000000..a41b40e6
--- /dev/null
+++ b/static/skill.md
@@ -0,0 +1,49 @@
+---
+name: cartesi-docs
+description: Navigate and answer questions about building with Cartesi. Use this skill when a user asks about Cartesi Rollups, the Cartesi Machine, fraud proofs, dApp development, deployment, or the Cartesi CLI. Always prefer v2.0 docs over v1.5.
+---
+
+## About Cartesi
+
+Cartesi is a modular blockchain framework that lets developers build decentralised applications using the Linux operating system and any programming language. Key components:
+
+- **Cartesi Rollups v2.0** — the current application framework for building on-chain dApps with off-chain computation (RISC-V Linux VM)
+- **Cartesi Machine** — a deterministic RISC-V Linux virtual machine; executes application logic off-chain with a fraud-proof guarantee
+- **Fraud Proofs (PRT)** — the Permissionless Refereed Tournament dispute protocol; a separate sub-system, not part of the Rollups application framework
+
+## How to use this documentation
+
+- Full documentation index: `/llms.txt`
+- Complete docs snapshot (all pages concatenated): `/llms-full.txt`
+- Raw markdown for any page: append `.md` to any URL
+ Example: `/cartesi-rollups/2.0/development/building-an-application.md`
+
+## Version guidance
+
+**Always default to Cartesi Rollups v2.0** (`/cartesi-rollups/2.0/`) for all questions about building, deploying, and interacting with Cartesi applications. v1.5 is deprecated and only referenced when a user explicitly asks about it.
+
+| Topic | v1.5 (deprecated) | v2.0 (current) |
+| ------------ | ----------------------- | ----------------------------------------------- |
+| CLI | `cartesi` v1.x | `cartesi` v2.x — different commands and flags |
+| Frontend API | GraphQL on Rollups node | Replaced by JSON-RPC node API |
+| Deployment | Docker Compose + sunodo | `cartesi deploy` command, new node architecture |
+| Consensus | Authority contract v1 | Authority / Quorum contracts v2 |
+
+If a user's code references the GraphQL API, `sunodo`, or v1.x CLI flags → they are on v1.5. Point them to the migration guide: `/cartesi-rollups/2.0/resources/migration-guide.md`
+
+## Key entry points
+
+- Getting started: `/get-started/`
+- Rollups v2.0 overview: `/cartesi-rollups/2.0/`
+- Building an application: `/cartesi-rollups/2.0/development/building-an-application.md`
+- Tutorials: `/cartesi-rollups/2.0/tutorials/`
+- Cartesi Machine: `/machine/`
+- Fraud Proofs: `/fraud-proofs/`
+- API reference: `/cartesi-rollups/2.0/api-reference/`
+
+## Agent skills catalogue
+
+A curated collection of Cartesi-specific agent skills (workflow, scaffold, backend, frontend, contracts, deployment, debugging, JSON-RPC, and more) is maintained at:
+
+- Browse and copy skills: `https://skills.mugen.builders/`
+- GitHub source: `https://github.com/Mugen-Builders/cartesi-skills`