diff --git a/changelog.mdx b/changelog.mdx index a47438a..8bc1732 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -14,7 +14,7 @@ Dated notes on what the products ship. Each entry names a change the app or the - **`/goal`** — persisted long-horizon objectives with `goal.json` on the session, an 8-turn budget, evidence-based completion, and a composer chip — merged to the CLI main branch in [CortexLM/cli #54](https://github.com/CortexLM/cli/pull/54). It ships with the next tagged release; `cortex upgrade` will pick it up. See [Goals](/cli/goal). - **One approval path** — the permission prompt is the locked inline numbered picker (run once · always allow in this project · edit command · decline), merged in [#53](https://github.com/CortexLM/cli/pull/53). See [Modes and permissions](/cli/modes-and-permissions). -- The Designer runtime pack — headless renders of every TUI state at 120×40 — is what the [CLI pages](/cli) now show. The README demo on a green macOS desktop is regenerated from the same chrome. +- The CLI runtime pack — headless renders of every TUI state at 120×40 — is what the [CLI pages](/cli) now show. The README demo on a green macOS desktop is regenerated from the same chrome. - Release: [v0.1.10 on GitHub](https://github.com/CortexLM/cli/releases/tag/v0.1.10). Update with `cortex upgrade`. diff --git a/cli/index.mdx b/cli/index.mdx index bcca9c0..b5091a6 100644 --- a/cli/index.mdx +++ b/cli/index.mdx @@ -58,24 +58,6 @@ cortex First session, `AGENTS.md`, choosing autonomy. - - Timeline rows, the composer, status line, queueing follow-ups, interrupting. - - - Everything after `/` — model, mode, permissions, plan, goal, sessions, MCP, diagnostics. - - - Agent / Plan / Ask, Spec, approvals, sandbox, the `permission` table, effort. - - - `/goal` — a persisted long-horizon objective that survives compaction and resume. - - - Resume, rewind, fork, export, import, share, lock, clean up. - - - Every binding, grouped by where it applies — plus the Ctrl+X overlay. - `cortex exec` and `cortex run` in scripts, GitHub Actions, GitLab CI. @@ -85,11 +67,22 @@ cortex MCP servers, skills, agents and subagents, hooks, plugins, themes. - - Outage copy, hosts that refuse, the agent that will not edit, MCP, quotas. - +## In the terminal + +The rest of the CLI reference lives in the sidebar under this tab: + +| Page | What it covers | +| --- | --- | +| [The TUI](/cli/tui) | Timeline rows, the composer, status line, queueing follow-ups, interrupting | +| [Slash commands](/cli/slash-commands) | Everything after `/` — model, mode, permissions, plan, goal, sessions, MCP, diagnostics | +| [Modes and permissions](/cli/modes-and-permissions) | Agent / Plan / Ask, Spec, approvals, sandbox, the `permission` table, effort | +| [Goals](/cli/goal) | `/goal` — a persisted long-horizon objective that survives compaction and resume | +| [Sessions](/cli/sessions) | Resume, rewind, fork, export, import, share, lock, clean up | +| [Keyboard shortcuts](/cli/keyboard) | Every binding, grouped by where it applies — plus the Ctrl+X overlay | +| [CLI troubleshooting](/cli/troubleshooting) | Outage copy, hosts that refuse, the agent that will not edit, MCP, quotas | + ## Conventions on these pages - Commands are written `cortex …`. The installed binary is `Cortex`; the installer adds `cortex` and `agent` symlinks, and both spellings work on case-insensitive filesystems. diff --git a/getting-started/quickstart.mdx b/getting-started/quickstart.mdx index 7ee2863..a3fb143 100644 --- a/getting-started/quickstart.mdx +++ b/getting-started/quickstart.mdx @@ -39,15 +39,6 @@ Cortex is one account across four products: **Chat**, **Code**, **Bot**, and **D Choose **Sign in to save your work** in the sidebar footer. A signed-in account keeps chats, projects, Library files, plans, and Bot routines across devices, and unlocks Code and Bot. See [Accounts](/getting-started/accounts). - - | Surface | First useful thing | Guide | - | --- | --- | --- | - | **Chat** | Create a project with standing instructions | [Chat quickstart](/chat/quickstart) | - | **Code** | Connect GitHub and start a Cloud session on a repository | [Code quickstart](/code/quickstart) | - | **Bot** | Create a bot and open its computer | [Bot quickstart](/bot/quickstart) | - | **CLI** | Install, sign in, run `cortex` in a project | [CLI quickstart](/cli/quickstart) | - | **Design** | Host a canvas from Chat or Code, then open it on desktop | [Design](/design) | - ## Install the desktop app or the CLI diff --git a/getting-started/settings.mdx b/getting-started/settings.mdx index 00ec2e8..1dbcc0a 100644 --- a/getting-started/settings.mdx +++ b/getting-started/settings.mdx @@ -59,17 +59,18 @@ Model availability depends on your plan. During peak hours new chats may fall ba ## Data & privacy -| Control | Default | Notes | +Where each control lives. What each one stores, and what it means, is on +[Security and privacy](/security/overview). + +| Control | Where | Notes | | --- | --- | --- | -| **Save chat history** | On | Conversations are kept in your account so you can pick them up on any device. *Coming soon* as a toggle. | -| **Improve the model** | Off | When on, a sample of your conversations may be reviewed to train future models. Your chats are never used without this setting. *Coming soon.* | -| **Necessary cookies** | Always on | Session, language, and this preference. Cortex cannot work without them. | -| **Optional analytics** | Off | Stays off until you allow it. Nothing in the current build loads an optional tracker. | -| **Memory** | — | Review or delete individual memories. See [Memory](/chat/memory). | -| **Two-factor authentication** | — | A signed-in account uses an authenticator app to confirm export and deletion. | -| **Your data** | — | **Export my data** and **Delete all data**. Deletion takes effect within 30 days. | - -See [Security](/security/overview) for what Cortex stores and where code runs. +| **Save chat history** | Data & privacy | On by default. *Coming soon* as a toggle. | +| **Improve the model** | Data & privacy | Off by default. Your chats are never used without this setting. *Coming soon.* | +| **Necessary cookies** | Data & privacy | Session, language, and this preference. Cortex cannot work without them. | +| **Optional analytics** | Data & privacy | Stays off until you allow it. Nothing in the current build loads an optional tracker. | +| **Memory** | Data & privacy | Review or delete individual memories. See [Memory](/chat/memory). | +| **Two-factor authentication** | Data & privacy | An authenticator app confirms export and deletion. | +| **Export my data / Delete all data** | Data & privacy | Deletion takes effect within 30 days. | ## Plan & billing diff --git a/images/cli/README.md b/images/cli/README.md index 1d167e9..edb8c20 100644 --- a/images/cli/README.md +++ b/images/cli/README.md @@ -9,7 +9,7 @@ exactly one page; no two files share a sha256. `docs/media/intro.gif` — the README demo: the signed lock TUI composited onto a photographed macOS desktop. Generated, not a live recording. Used on `cli/index`. -## `runtime/` — Designer cli pack +## `runtime/` — CLI runtime pack Headless `MockTerminal` renders of the live session chrome, vendored byte-for-byte from CortexLM/cli tip `4d41ef362481ec816ac395e0e64fe6a54327de14` diff --git a/scripts/check-docs-site.mjs b/scripts/check-docs-site.mjs index f7447c2..6345605 100644 --- a/scripts/check-docs-site.mjs +++ b/scripts/check-docs-site.mjs @@ -201,6 +201,35 @@ function assertNavPagesExist(parsed) { } } +/** + * An MDX page no navigation entry reaches is dead weight: it still gets + * indexed, and still shows up in search — but no reader can navigate to it. + * This is how the old tree accumulated a second hub for every product + * (`chat/overview` beside `chat/index`) and pages whose only inbound links + * were from other orphans. + * + * The home page is reachable from the navbar's `/` link, which `pushNavSlug` + * drops as a non-slug, so it is exempted by name. + */ +function assertNoOrphanPages(docsJson) { + let parsed; + try { + parsed = JSON.parse(docsJson); + } catch { + return; // already reported as invalid JSON + } + const nav = new Set(navPages(parsed)); + for (const file of walk(ROOT)) { + if (!file.endsWith('.mdx')) continue; + const slug = relative(ROOT, file).replace(/\.mdx$/, ''); + if (slug === 'index') continue; + if (nav.has(slug) || nav.has(slug.replace(/\/index$/, ''))) continue; + fail( + `${slug}.mdx is not reachable from docs.json navigation (orphaned page)`, + ); + } +} + const AUTH_INTERNALS = [ { pattern: /\/auth\//, label: '/auth/' }, { pattern: /\/oauth\//, label: '/oauth/' }, @@ -210,6 +239,46 @@ const AUTH_INTERNALS = [ { pattern: /client_secret/i, label: 'client secret' }, ]; +/** + * Staging must never reach the public site again. + * + * `docs.cortex.foundation` is the public Mintlify site, and it once publicly + * served `/staging/*` pages plus a Staging collection. Deleting those files is + * not enough: a re-added `staging/…` page, a nav entry, or a redirect into one + * would put pre-prod copy back on the public domain. This holds the line + * mechanically, the same way the auth-internal check does. + */ +function assertNoStagingNav(docsJson) { + let parsed; + try { + parsed = JSON.parse(docsJson); + } catch { + return; // already reported as invalid JSON + } + const seen = new Set(); + for (const slug of navPages(parsed)) { + if (!/(^|\/)staging(\/|$)/i.test(slug) || seen.has(slug)) continue; + seen.add(slug); + fail(`docs.json navigation must not publish a staging page (${slug})`); + } + const redirectSources = Array.isArray(parsed.redirects) ? parsed.redirects : []; + for (const rule of redirectSources) { + if (typeof rule?.destination === 'string' && /(^|\/)staging(\/|$)/i.test(rule.destination)) { + fail(`docs.json redirect ${rule.source} points at a staging page`); + } + } +} + +function assertNoStagingContent(rel, text) { + if (!rel.endsWith('.mdx')) return; + if (/\/staging(\/|$)/.test(text)) { + fail(`${rel} links to a staging path (public docs have no staging mirror)`); + } + if (/\bstaging\b/i.test(text) && !/no staging|not staging|retired/i.test(text)) { + fail(`${rel} tells readers about staging (public docs are production only)`); + } +} + function assertNoAuthInternals(rel, text) { if (!rel.endsWith('.mdx')) return; for (const { pattern, label } of AUTH_INTERNALS) { @@ -310,6 +379,37 @@ for (const extra of pageCodes) { } } +/** + * The catalog table in `problems/index.mdx` is hand-maintained while the pages + * beside it are generated in lockstep with the backend. That is the same decay + * this file exists to catch: a new code lands as a page, the catalog keeps + * listing the old set, and the index — the page a reader actually lands on — + * silently stops being complete. + */ +function assertCatalogCoversPages() { + const rel = 'problems/index.mdx'; + if (!existsSync(join(ROOT, rel))) { + fail(`${rel} is missing (problem catalog index)`); + return; + } + const catalog = read(rel); + const listed = new Set( + [...catalog.matchAll(/\]\(\/problems\/([a-z_]+)\)/g)].map((m) => m[1]), + ); + for (const code of pageCodes) { + if (!listed.has(code)) { + fail(`${rel} does not link \`${code}\`; every problem page belongs in the catalog`); + } + } + for (const code of listed) { + if (!pageCodes.has(code)) { + fail(`${rel} links \`${code}\`, which has no page at problems/${code}.mdx`); + } + } +} + +assertCatalogCoversPages(); + if (!existsSync(join(docsRoot, 'docs.json'))) { fail('docs.json is missing (Mintlify site config)'); } else { @@ -321,6 +421,8 @@ if (!existsSync(join(docsRoot, 'docs.json'))) { fail('docs.json still names docs.cortex.sh'); } assertDocsChrome(docsJson); + assertNoStagingNav(docsJson); + assertNoOrphanPages(docsJson); } for (const rel of FORBIDDEN_AUTH_PAGES) { @@ -363,6 +465,7 @@ for (const file of docsFiles) { ); } assertNoAuthInternals(rel, text); + assertNoStagingContent(rel, text); if (BACKEND === null) continue; for (const path of documentedV1Paths(text)) { const norm = normalizePath(path); diff --git a/scripts/tests/check-docs-site.test.sh b/scripts/tests/check-docs-site.test.sh index e3de33d..c6630cb 100755 --- a/scripts/tests/check-docs-site.test.sh +++ b/scripts/tests/check-docs-site.test.sh @@ -58,7 +58,7 @@ RS "groups": [ { "group": "Problems", - "pages": ["problems/not_found", "problems/internal"] + "pages": ["problems/index", "problems/not_found", "problems/internal"] } ] } @@ -79,6 +79,16 @@ title: "${code}" | \`GET\` | \`/v1/conversations\` | MDX done + cat > "$dest/site/problems/index.mdx" <<'MDX' +--- +title: "Problem catalog" +--- + +| Code | HTTP | +| --- | --- | +| [`not_found`](/problems/not_found) | 404 | +| [`internal`](/problems/internal) | 500 | +MDX } must_fail() { @@ -318,7 +328,7 @@ cat > "$goodroot/site/docs.json" <<'JSON' { "group": "Problems", "root": "problems/not_found", - "pages": ["problems/internal"] + "pages": ["problems/internal", "problems/index"] } ] } @@ -362,4 +372,124 @@ cat > "$missinghref/site/docs.json" <<'JSON' JSON must_fail "$missinghref" "missing-mintlify-page" +# Staging must not return to the public site. docs.cortex.foundation served a +# /staging collection publicly once; a re-added page, nav entry, or redirect +# would put pre-prod copy back on the domain. +stagingnav="$tmp/staging-nav" +seed "$stagingnav" +mkdir -p "$stagingnav/site/staging" +cat > "$stagingnav/site/staging/index.mdx" <<'MDX' +--- +title: "Index" +--- +Staging mirror — unpublished drafts / pre-prod docs +MDX +cat > "$stagingnav/site/docs.json" <<'JSON' +{ + "name": "Cortex", + "logo": { "href": "https://docs.cortex.foundation" }, + "navbar": { + "links": [ + { "label": "Home", "href": "/" }, + { "label": "Documentation", "href": "/problems/not_found" } + ] + }, + "navigation": { + "tabs": [ + { + "tab": "Staging", + "groups": [ + { "group": "Drafts", "pages": ["staging/index"] } + ] + } + ] + } +} +JSON +must_fail "$stagingnav" "staging" + +# A redirect into a staging path is the same leak by another route. +stagingredirect="$tmp/staging-redirect" +seed "$stagingredirect" +cat > "$stagingredirect/site/docs.json" <<'JSON' +{ + "name": "Cortex", + "logo": { "href": "https://docs.cortex.foundation" }, + "navbar": { + "links": [ + { "label": "Home", "href": "/" }, + { "label": "Documentation", "href": "/problems/not_found" } + ] + }, + "redirects": [ + { "source": "/drafts", "destination": "/staging/index" } + ], + "navigation": { + "tabs": [ + { + "tab": "API", + "groups": [ + { "group": "Problems", "pages": ["problems/not_found", "problems/internal"] } + ] + } + ] + } +} +JSON +must_fail "$stagingredirect" "staging" + +# Copy that sends a reader to a staging host or path must fail even when the +# page itself is fine. +stagingcopy="$tmp/staging-copy" +seed "$stagingcopy" +printf '\nUse the staging environment at `/staging/api` for pre-prod keys.\n' \ + >> "$stagingcopy/site/problems/not_found.mdx" +must_fail "$stagingcopy" "staging" + +# A page no navigation entry reaches still gets indexed, but no reader can +# navigate to it. That is how the tree accumulated a second hub for every +# product. +orphan="$tmp/orphan-page" +seed "$orphan" +cat > "$orphan/site/problems/leftover.mdx" <<'MDX' +--- +title: "Leftover" +--- + +`type` is `https://docs.cortex.foundation/problems/leftover`. +MDX +must_fail "$orphan" "orphaned page" + +# The catalog index is hand-maintained while the pages beside it are generated +# in lockstep with the backend. A page the catalog forgets is invisible to the +# reader who lands on the index. +drift="$tmp/catalog-drift" +seed "$drift" +cat > "$drift/site/problems/index.mdx" <<'MDX' +--- +title: "Problem catalog" +--- + +| Code | HTTP | +| --- | --- | +| [`not_found`](/problems/not_found) | 404 | +MDX +must_fail "$drift" "does not link \`internal\`" + +# And the reverse: a catalog entry with no page behind it. +dangling="$tmp/catalog-dangling" +seed "$dangling" +cat > "$dangling/site/problems/index.mdx" <<'MDX' +--- +title: "Problem catalog" +--- + +| Code | HTTP | +| --- | --- | +| [`not_found`](/problems/not_found) | 404 | +| [`internal`](/problems/internal) | 500 | +| [`ghost`](/problems/ghost) | 500 | +MDX +must_fail "$dangling" "no page at problems/ghost.mdx" + echo "check-docs-site: ok" diff --git a/security/overview.mdx b/security/overview.mdx index ca25058..340a1cd 100644 --- a/security/overview.mdx +++ b/security/overview.mdx @@ -31,6 +31,9 @@ From **Settings → Data & privacy**, in the product's own words: your account d | **Two-factor authentication** | — | A signed-in account uses an authenticator app to confirm export and deletion. | | **Export my data / Delete all data** | — | Export everything held, or delete it permanently. Deletion takes effect within 30 days. | +These live under **Settings → Data & privacy**; [Settings](/getting-started/settings) +lists where each control is. The table above is what each one stores. + ## Permissions A guest cannot connect a plugin or MCP server, hold a GitHub grant, create a bot, or open Code's working UI. That is fail-closed by design: a guest session cannot be signed back into to revoke a grant later, so it is never allowed to create one. diff --git a/status.mdx b/status.mdx index b38cc13..fa004fa 100644 --- a/status.mdx +++ b/status.mdx @@ -8,17 +8,13 @@ keywords: ["uptime", "outage", "incident", "maintenance", "availability"] Cortex -Cortex publishes live component health, incident history, and scheduled maintenance on the public status page. +Live component health, incident history, and scheduled maintenance are published on **[status.cortex.foundation](https://status.cortex.foundation)**. Bookmark that page; this article explains what it covers and how it relates to product troubleshooting.

Open status.cortex.foundation Troubleshooting

- -The canonical status URL is **[status.cortex.foundation](https://status.cortex.foundation)**. Bookmark that page for outages and planned maintenance. This docs article explains what it covers and how it relates to product troubleshooting. - - ## What we report | Component | What it covers | @@ -33,8 +29,8 @@ Component names stay product-facing. Individual incidents may mark one or more o ## During an incident -1. Check **[status.cortex.foundation](https://status.cortex.foundation)** for the current banner and component states. -2. Subscribe on that page if you want email (or other) updates for the next change. +1. Check the status page for the current banner and component states. +2. Subscribe there if you want updates for the next change. 3. Keep any `request_id` from an error in the app — see [Troubleshooting](/getting-started/troubleshooting) and the [problem catalog](/problems). User-facing error text names a Cortex surface, never a vendor. Status updates are the place for fleet-wide notices. @@ -48,10 +44,6 @@ User-facing error text names a Cortex surface, never a vendor. Status updates ar | [Security and privacy](/security/overview) | Data handling — not availability | | [Changelog](/changelog) | What shipped — not outages | -## Brand - -Status communications use Cortex green (`#1F4945`) and the Cortex logo. The status site is hosted under the `cortex.foundation` domain so it stays available when you need it most. - ## Related - [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means.