diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..99666af --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto eol=lf +*.mdx text eol=lf +*.json text eol=lf +*.mjs text eol=lf +*.sh text eol=lf +*.svg text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 993c320..1ae908d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,9 @@ jobs: with: node-version: 22 - run: node scripts/check-docs-site.mjs + - run: node scripts/check-docs-content.mjs - run: bash scripts/tests/check-docs-site.test.sh + - run: bash scripts/tests/check-docs-content.test.sh - run: node scripts/tests/docs-ui.test.mjs - name: Validate the Mintlify build run: npm exec --yes --package=mint@4.2.876 -- mint validate diff --git a/AGENTS.md b/AGENTS.md index a825bbc..ecf1d30 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,31 +1,38 @@ # Cortex public documentation This is the Mintlify site for `docs.cortex.foundation`. Edit the site at the -repository root, not in `apps/docs`. Preview and validation commands are in -`README.md`. +repository root. Preview and validation commands are in `README.md`. -- Keep product copy in English and use the Cortex product names and domains. -- Do not publish authentication/session internals, credentials, private API - routes, farm details, or backend operator runbooks. -- Preserve the Home + Documentation navbar and ink-on-cream CTAs. -- Keep navigation a flat list of top-level groups (`navigation.groups`). - `navigation.tabs` renders a product dropdown in the navbar; the hubs already - are that second level, so a tab makes the reader pick Chat twice. -- Keep every navigation slug backed by a page and every problem page's - `type` URL on `https://docs.cortex.foundation/problems/{code}`. -- One hub page per product (`/index.mdx`). Do not add a second - overview page beside it, and give every page a `title`, a `description`, - and a closing **Related** or **Next** section. -- Keep `description` under 160 characters so it is not truncated in search - results and link previews. Where the product's sidebar label differs from - the page title (the sidebar says **Artifacts**, the page is **Library**), - add the label to `keywords` so either term finds the page. -- Run `node scripts/check-docs-site.mjs` and - `bash scripts/tests/check-docs-site.test.sh`, then - `node scripts/tests/docs-ui.test.mjs` and +- Keep product copy in English and use the Cortex product names and domains: + Cortex Chat, Cortex Code, Cortex Bot, Cortex Design, Cortex Security, the + Cortex CLI, Cortex Bounty; `cortex.foundation`, `docs.cortex.foundation`, + `status.cortex.foundation`, `software.cortex.foundation`. +- The site is end-user documentation. Do not publish sign-in wire protocols, + session or token internals, credentials, private API routes, infrastructure + details, vendor names, or backend operator runbooks. Competitor product + names never appear in copy, titles, or `docs.json`. +- The site carries **no images**. Every page has an `icon` in its frontmatter + and every `` has an `icon`; icons are Font Awesome names (the Mintlify + starter default, so `icons.library` stays unset). Do not add ``, + ``, markdown images, or an `image:` field. +- Navigation is `navigation.tabs`: one tab per application (Get started, Chat, + Code, Bot, CLI, Design, Security, Reference), each tab a list of groups, each + tab and group with an icon. Every product tab opens on its hub page + (`/index.mdx`). Do not add a second overview page beside a hub. +- Every page has a unique `title`, a `description` under 160 characters, and a + closing **Related** section. Where a sidebar label differs from the title, + set `sidebarTitle` and add the alternative name to `keywords`. +- Keep every navigation slug, footer link, redirect destination, and internal + href backed by a page, and every problem page's `type` URL on + `https://docs.cortex.foundation/problems/{code}`. +- Only document API paths on `reference/errors`, `bounty/public-api`, and the + problem pages, and only paths the backend router registers. +- Run `node scripts/check-docs-site.mjs`, + `bash scripts/tests/check-docs-site.test.sh`, + `node scripts/tests/docs-ui.test.mjs`, then `npm exec --yes --package=mint@4.2.876 -- mint validate` before committing. - For error-code or endpoint changes, also run the checker with a backend - checkout as its first argument. Coordinate the two PRs; the backend owns - the API contract and checks this repository in its CI. + checkout as its first argument. Coordinate the two PRs; the backend owns the + API contract and checks this repository in its CI. - Do not change the Mintlify integration, custom domain, or DNS without an explicit request. diff --git a/README.md b/README.md index 2d75754..f218d3d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # Cortex docs (`docs.cortex.foundation`) -Public product documentation for **Cortex Chat**, **Cortex Code**, **Cortex Bot**, the **Cortex CLI**, -and **Cortex Design**. This site is **end-user visible**. It does **not** document -login, sessions, refresh tokens, OAuth wire protocol, or other non-public APIs. - -This repository is a [Mintlify](https://mintlify.com) site, migrated from -`CortexLM/backend` at `782b054` (the former `apps/docs` directory). -Engineering / operator documentation stays in -[`CortexLM/backend/docs`](https://github.com/CortexLM/backend/tree/main/docs) -(runbooks, SOC 2 notes, farm internals). Do not merge the two trees. +Public documentation for the Cortex applications: **Cortex Chat**, **Cortex +Code**, **Cortex Bot**, the **Cortex CLI**, **Cortex Design**, and **Cortex +Security**, plus a Reference tab (errors, models, limits, privacy, status, +the Bounty program, and the changelog). The site is **end-user visible**. It +does not document sign-in internals, private API routes, or infrastructure. + +This repository is a [Mintlify](https://mintlify.com) site built from the +Mintlify starter kit (`mint` theme, Font Awesome icons, tabs in the navbar). +Engineering and operator documentation stays in +[`CortexLM/backend/docs`](https://github.com/CortexLM/backend/tree/main/docs). +Do not merge the two trees. ## Preview @@ -18,69 +20,45 @@ cd docs npx mint dev --no-open ``` -Requires Node 20.17+. The site is intended to publish at -`https://docs.cortex.foundation`. Connecting the custom domain is an operator -step in the Mintlify dashboard. Connect `CortexLM/docs`, branch `main`, with -the content directory set to the repository root (not `apps/docs`). +Requires Node 20.17+. The site publishes at `https://docs.cortex.foundation` +from branch `main`, with the content directory set to the repository root. ### Custom-domain DNS Every Cortex custom domain that CNAMEs to a third-party hostname is a -**Direct CNAME (DNS only)** — `docs.cortex.foundation` (Mintlify), +**Direct CNAME (DNS only)**: `docs.cortex.foundation` (Mintlify), `status.cortex.foundation` (status page), and the -`software.cortex.foundation` / `releases.cortex.foundation` R2 custom -domains owned by -[`CortexLM/backend`](https://github.com/CortexLM/backend) -(`docs/software-cdn.md`). +`software.cortex.foundation` / `releases.cortex.foundation` download hosts +owned by [`CortexLM/backend`](https://github.com/CortexLM/backend). -> **Use a Direct CNAME (DNS only). Do not enable orange-cloud Proxied** — that -> causes Cloudflare **Cross-User Banned** (Error 1014). +> **Use a Direct CNAME (DNS only). Do not enable proxying** on these records. ## Structure -Mintlify is the single source of truth for the public docs. There is no -downstream mirror to sync: the site publishes from this repository, branch -`main`, and `docs.json` is the whole navigation. +`docs.json` is the whole navigation. It uses `navigation.tabs`, one tab per +application, so a reader picks the product from the navbar: -| Tab | Holds | Entry point | +| Tab | Holds | Opens on | | --- | --- | --- | -| Get started | Quickstart, what Cortex is, accounts, plans, settings, downloads, help | `getting-started/quickstart` | -| Chat | The conversation product — projects, Library, plans, models, tools, research, media | `chat/index` | -| Code | The coding agent — sessions, modes, GitHub, runtimes, review | `code/index` | -| Bot | The computer-using agent — computer, tools, approvals, routines, skills | `bot/index` | -| CLI | The terminal front-end to Code — install, TUI, slash commands, sessions, headless, extend | `cli/index` | -| Design | Canvases and the Design library | `design/index` | -| API | The RFC 9457 problem format and the catalog of error codes | `api/overview` | -| Changelog | Dated release notes, and the deferred Platform API | `changelog` | - -Navigation is **one flat list of top-level groups** — `navigation.groups`, not -`navigation.tabs`. A tab renders a second-level switcher in the navbar, and the -product hubs already are that second level; the sidebar would otherwise ask a -reader to pick Chat twice. `docs-ui.test.mjs` fails if `tabs`, `dropdowns`, or -`products` come back, or if a product group stops opening its hub. - -Each product group is flat: the hub, then every page of that product in reading -order, then its troubleshooting page. Nested groups inside a product group are -for reference material only — the problem catalog is the one that remains. - -Each product tab opens on a single hub page (`/index.mdx`). Do not -re-introduce a second overview page beside it — one entry point per product, -with the task guides beneath it in the sidebar. - -Every page ends with a **Related** or **Next** section so a reader is never at -a dead end, and every page carries a `title` and a `description` in its -frontmatter. Product pages also carry an `image` for link previews. - -Keep `description` under 160 characters — longer text is truncated in search -results and link previews. Titles are unique across the site; where two pages -would otherwise collide (`Sessions` in Code and in the CLI, `Canvases` in Chat -and in Design) the title carries the product and `sidebarTitle` keeps the +| Get started | Home, quickstart, what Cortex is, choosing a product, accounts and sign-in, two-factor, plans and quotas, settings, data and privacy, notifications, interface language, ways to run Cortex, the desktop app, troubleshooting, shortcuts, bug reports, FAQ, glossary | `index` | +| Chat | Conversations, models and thinking, attachments, streaming and reconnects, voice, canvases, document export, projects, Library, file sharing, memory, Planning, scheduled tasks, built-in tools, Deep Research, image generation, origin check, Cortex Data, skills, Connectors, MCP servers, page tools, sharing and teams, troubleshooting | `chat/index` | +| Code | Sessions, Ask / Plan / Agent, approvals, changes and diffs, tickets, cloud runtimes, environments and images, machines, SSH hosts, desktop, GitHub, repositories and branches, automations, notifications, usage, settings, integrations, CLI pointer, review pointer, troubleshooting | `code/index` | +| Bot | Create a bot, talking to a bot, computer, tools, approvals and tool policy, memory, skills, routines, tasks and subagents, connected apps and secrets, inbox, channels, sharing, teach from a demonstration, Bot desktop app, troubleshooting | `bot/index` | +| CLI | Install, sign in, quickstart, the TUI, modes and permissions, Plan and Spec modes, sessions, goals, slash commands, shortcuts, tools, cloud / this PC / SSH, editor integration, headless runs, CI cookbook, configuration, environment variables, data locations, permission policy, MCP, skills, agents and subagents, hooks, plugins, themes, command reference, troubleshooting | `cli/index` | +| Design | Quickstart, canvases, generate and edit, versions, library, export, Bot jobs, Connectors, Design desktop app, settings, troubleshooting | `design/index` | +| Security | Quickstart, how a review works, checks and comments, review policy, repository scans, Cortex Agent runs, installation and repositories, troubleshooting | `security/index` | +| Reference | Errors and the problem catalog, models, limits and quotas, security and privacy, system status, Platform API, the Bounty program (pair a hotkey, file a report, verdicts and scoring, Transparency API), changelog | `reference/errors` | + +Each product tab opens on a single hub page (`/index.mdx`) with a card +per page of the tab. Every page carries a `title`, a `description` under 160 +characters, an `icon`, and ends with a **Related** section so a reader is +never at a dead end. Titles are unique across the site; where two pages would +otherwise collide (`Sessions` in Code and in the CLI, `Skills` in Chat, Bot, +and the CLI) the title carries the product and `sidebarTitle` keeps the sidebar short. -Where the product's sidebar label differs from the page title, list the label -in `keywords` so either term finds the page. The sidebar says **Artifacts**; -the page is [Library](/chat/library). It says **Planning**; the page is -[Plans](/chat/plans). It says **Agents**; the page is [Cortex Bot](/bot). +The site has **no images**. Every visual is an icon (Font Awesome, the Mintlify +starter default). ## Checks @@ -91,8 +69,9 @@ node scripts/tests/docs-ui.test.mjs npm exec --yes --package=mint@4.2.876 -- mint validate ``` -The **Docs site** CI job checks navigation, problem-page URLs and the public -content rules without needing access to the backend. +The **Docs site** CI job checks navigation, problem-page URLs, frontmatter, +internal links, and the public content rules without needing access to the +backend. To also validate against the real API, pass a backend checkout: @@ -106,41 +85,13 @@ merge the docs page first, then update the backend's checkout pin in the PR that adds the code. The full check fails when: - `PROBLEM_TYPE_BASE` is not `https://docs.cortex.foundation/problems` -- an `ErrorCode` is missing its `/problems/{code}` page -- a `docs.json` navigation slug or internal href has no matching MDX page +- an `ErrorCode` is missing its `/problems/{code}` page, or a page documents a code the API does not emit +- a `docs.json` navigation slug, group root, navbar or footer href, redirect destination, or internal link has no matching MDX page - a documented `/v1/…` path is not registered in `crates/cortex-api/src/router.rs` -- this tree names a problem-docs host other than `docs.cortex.foundation` -- the top navbar is not Home + Documentation, or it carries Chat | Code | Bot chrome / `navbar.primary` -- the home page uses Mintlify Cards as brand-green Install CTAs instead of `.ink-btn` -- public MDX documents `/auth/`, `/oauth/`, `refresh_token`, WorkOS, or `cortex_rt` -- `api/authentication.mdx` or `api/oauth.mdx` exist, or the API group lists them - -Do not invent endpoints. There is no inference Platform API section here — see -`platform.mdx`. Sign in via the app; this tree has no auth stack. - -`scripts/check-docs-site.mjs` enforces all of the above, including that every -`docs.json` navigation slug resolves to a page. Run it before pushing; a -sidebar link with no MDX behind it would otherwise publish as a 404. - -## Visuals - -Brand green `#1F4945` is for doodle accents, illustration focus rings, and -window frames — not hero CTAs. Home and card actions use **ink on cream** -(`.ink-btn` in `custom.css`) — filled ink, quiet outline; dark mode inverts -to cream ink. Do not add a brand-green Install / `navbar.primary` button. - -Guide heroes that depict the product are **live Cortex screenshots** in -`images/product/` plus CLI canon in `images/cli/` (vendored from -CortexLM/cli `docs/media/`). **Every page shows a distinct capture** — no -product frame is reused on two pages; `images/product/README.md` maps each -file to the page that uses it, and lists member-only surfaces still to be -captured. Do not add abstract product-window SVGs. `images/frames/` is -retired. Banner card art (`images/banners/`) belongs inside `CardGroup` -grids on Home and the hubs — never as a lone full-width `Card`. Cream, ink, -`#1F4945` focus — no violet. - -Top navbar is Mintlify **Home + Documentation**, not the Chat | Code | Bot -product switcher. Get started / Chat / Code / Bot / CLI / Design stay as -top-level **sidebar groups**, not navbar tabs: a tab would put the product -switcher back in the navbar as a dropdown. Competitor product names never -appear in copy, titles, or `docs.json`. +- a page carries an image, lacks a title, description, or icon, repeats another page's title, or has a description over 160 characters +- navigation is not `navigation.tabs` with a tab for each of Chat, Code, Bot, CLI, Design, and Security, each tab and group carrying an icon +- public MDX documents `/auth/`, `/oauth/`, `refresh_token`, the identity vendor, or the session cookie +- `api/authentication.mdx` or `api/oauth.mdx` exist, or the navigation lists them + +Do not invent endpoints. There is no inference Platform API section here; see +`reference/platform-api.mdx`. Sign in via the app; this tree has no auth stack. diff --git a/api/errors.mdx b/api/errors.mdx deleted file mode 100644 index 2c4211b..0000000 --- a/api/errors.mdx +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: "Errors" -description: "Every Cortex failure is an RFC 9457 problem document. Branch on code, read request_id, and know which fields are safe to render." -keywords: ["problem json", "error handling", "status codes"] ---- - -Every failure Cortex returns is an `application/problem+json` document: - -```json -{ - "type": "https://docs.cortex.foundation/problems/not_found", - "title": "Not found", - "status": 404, - "code": "not_found", - "detail": "No conversation with id cnv_x.", - "request_id": "req_…" -} -``` - -## Fields - -| Field | Always present | What to do with it | -| --- | --- | --- | -| **`code`** | Yes | **This is the contract.** Branch on `code`, never on `title` or `detail`. The same code means the same thing on every surface. | -| **`type`** | Yes | A dereferenceable URL for the code — [Problem catalog](/problems). Stable; safe to link. | -| **`status`** | Yes | The HTTP status. Present in the body as well so a logged document is self-describing. | -| **`request_id`** | Yes | Always present, always safe to show or log. Quote it when reporting a problem. | -| **`title`** | Yes | English, for logs and humans reading raw JSON. Do not render it to end users. | -| **`detail`** | Sometimes | English, for logs and humans reading raw JSON. Do not render it to end users. | - -## Rendering rules - -The web app renders catalog copy for a code rather than the wire text. If you are building a client against these documents, do the same. - -- **Render your own copy** for `code`. The catalog page for each code explains the situation in product language. -- **Do not render `detail`.** It is diagnostic text, and it may name an internal component or a specific resource id. -- **Three codes may show `detail` as a secondary line**: `validation_failed`, `bad_request`, and `invalid_state`. Even there it is supplementary, not the message. -- **User-facing text never names a vendor.** `detail` names a Cortex surface — *The audio service is temporarily unavailable.* — never a subprocessor. - -## Handling a code - -| Situation | What to do | -| --- | --- | -| The catalog marks the code **Retryable: yes** | Retry after the delay the response suggests, then back off. | -| The catalog marks it **Retryable: no** | Retrying the same request will fail the same way. Change the request, the plan, or the state. | -| You see `rate_limited` or `quota_exceeded` | Both are HTTP 429 but mean different things — transport throttling versus a plan window. See [Plans and quotas](/getting-started/plans). | -| You see `internal` or an upstream code | Keep the `request_id`. Check [status.cortex.foundation](https://status.cortex.foundation) if it repeats. | - -Full list with statuses and retry guidance: [Problem catalog](/problems). - -## Related - -- [Problem catalog](/problems) — every code, status, and retry answer. -- [Public API](/api/overview) — what this tab covers. -- [Troubleshooting](/getting-started/troubleshooting) — what to do about a message you see in the product. diff --git a/api/overview.mdx b/api/overview.mdx deleted file mode 100644 index 81b4606..0000000 --- a/api/overview.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Public API" -description: "What this site documents about the Cortex API — the RFC 9457 problem format and its type URIs. Sign in via the app." -keywords: ["reference", "error format", "RFC 9457"] ---- - -Cortex is used through its apps, not through a public API you write against. This tab documents the one part of the wire contract that is public and stable: the shape of an error. - -**Sign in at [cortex.foundation](https://cortex.foundation).** The CLI and the desktop apps use the same account. This site does not document login, sessions, or identity-provider wire protocol. - -## What is public here - -| Page | What it covers | -| --- | --- | -| [Problem catalog](/problems) | Every `type` URI — `https://docs.cortex.foundation/problems/{code}` — with its HTTP status and whether retrying helps | -| [Errors](/api/errors) | How a problem document is shaped and which fields you can rely on | -| [Platform API](/platform) | Why there is no inference API yet | - -Product guides live under their own tabs: [Chat](/chat), [Code](/code), [Bot](/bot), [CLI](/cli), [Design](/design). - -## Why the error format is public - -Every Cortex surface — the web app, the desktop apps, and the CLI — reads the same problem documents. When something fails, the message you see names a Cortex surface and carries a stable `code`. Publishing the codes means the message in the product, the message in the terminal, and this catalog all say the same thing. - -Connect apps and GitHub from **Settings** and **Customize** in the product. There is no public plugin webhook catalog on this site. - -## How a problem document is built - -| Field | Comes from | -| --- | --- | -| `type` | The base `https://docs.cortex.foundation/problems` plus the `code` | -| `code` | A fixed snake_case identifier — the part to branch on | -| `status` | The HTTP status the response carries | -| `request_id` | Per request; the value to quote when reporting a problem | -| `title`, `detail` | English diagnostic text for logs, not for end users | - -Because the base is fixed and the path is the `code`, a `type` URL resolves to a page on this site. That is the whole reason the catalog exists: an error can point at its own explanation instead of leaving a reader with a bare status. - -## What is not here - -- Authentication, session cookies, device codes, or identity-provider internals. -- The app's private session API. It is not a supported integration surface. -- An inference Platform API. See [Platform API](/platform) — no endpoints, SDKs, or keys exist. - -## Related - -- [Errors](/api/errors) — the problem document format. -- [Problem catalog](/problems) — all codes in one table. -- [Platform API](/platform) — why there is no inference API. -- [Troubleshooting](/getting-started/troubleshooting) — what to do when you see one. diff --git a/bot/approvals.mdx b/bot/approvals.mdx index f460c5e..75a9a96 100644 --- a/bot/approvals.mdx +++ b/bot/approvals.mdx @@ -1,52 +1,119 @@ --- -title: "Approvals" -description: "Allow / Deny / Always. A bot parks consequential steps — connected-app changes and dangerous computer actions — and nothing runs until you choose." -keywords: ["permissions", "Allow", "Deny", "Always", "parked step"] +title: "Approvals and tool policy" +description: "Allow, Deny and Always: how a bot parks a consequential step, which tools always ask, and the rules and tiers that decide before you are asked." +icon: "hand" --- -A bot can act, so it asks first. When it reaches a step that changes something in a connected app or could damage its computer, it **parks** the action and shows an approval widget in the conversation. The widget names the tool and what it is about to do. +A bot can act on its own computer and in the apps you connected to it, so it asks before it does anything consequential. When it reaches such a step the turn **parks**: the tool does not run, the bot waits, and you get a widget naming the tool, the bot's reason for wanting it and the exact arguments it intends to use. + +This page covers the three choices, which tools always ask and which never do, the automatic policy that decides before you are involved, where pending approvals show up, and what happens when something cannot be settled. **Cortex Bot** is the only Cortex product with per-tool approval, because a bot runs without a round limit and with a machine of its own. ## The three choices +One sentence from the product carries the whole model: `Allow runs the parked tool. Deny does not. Always writes a rule.` + | Choice | What happens | | --- | --- | -| **Allow** | Runs the parked action, this once | -| **Deny** | Does not run it. The bot continues without that step and can propose something else. | -| **Always** | Runs it, and remembers the choice for the next time this same kind of step appears | +| **Allow** | The parked tool runs, this once, with the real arguments, and the turn continues from the real result | +| **Deny** | The tool does not run and nothing is written. The bot is told why and can propose something else | +| **Always** | Writes a rule so that tool does not ask again on this bot, then runs it | -**Always** is scoped to that kind of step — not a blanket for every tool the bot has. Confirming **runs** the parked action; it is not a preview. +**Allow** is not "continue" and it is not a preview. It executes the exact call you are looking at. **Deny** never writes a rule, so the same tool will ask again next time, and **Allow** does not stop the asking either: only **Always** changes what happens next. The widget states its own scope, `Always grants this tool for this Bot until its approval rule is removed.`, and the Approvals page repeats it as `Always skips Ask the next time this bot uses that tool.` -## What parks - -| Category | Examples | -| --- | --- | -| Connected-app changes | Creating or editing records, sending messages, anything that writes through a plugin | -| Dangerous computer steps | Deleting files, installing software, commands with broad effect | - -Reading, browsing, and taking screenshots do not park; they are how the bot works. + +Approving is not a way around a block. If a rule denies that tool between the moment it parked and the moment you choose, the call is evaluated again and refused. An approval is consent, not an override. + ## Read before you choose - - The widget says which tool wants to run and what it will do. + + The widget asks `Allow {tool}?` and shows the bot's reason underneath. + + + The parked arguments are shown in full: the command, the path, the text it wants to type. This is the one place they are displayed, so this is where you check them. - - The live desktop shows the state the bot is in. See [Computer](/bot/computer). + + The live desktop shows the state the bot is actually in. See [Computer](/bot/computer). - Allow, Deny, or Always. The bot waits; a parked step never times out into a silent yes. + **Allow**, **Deny** or **Always**. Nothing times out into a silent yes, and a parked tool waits as long as it takes. -## Approvals elsewhere +## Which tools always ask + +Eleven tools always ask before they run: `shell`, `write`, `edit`, `code_agent`, `browser`, `grounded_click`, `type`, `hotkey`, `drag`, `open_app` and `switch_app`. -| Surface | Control | +Twenty never ask: `read`, `screenshot`, `scroll`, `wait`, `save_note`, `web_search`, `web_fetch`, `ask_user`, `secret_request`, `send_to_user`, `notify`, `update_memory`, `skill`, `routine`, `task`, `send_to_agent`, `create_agent`, `create_channel`, `read_artifact` and `grep_artifact`. + +A tool on neither list is allowed to run. The two lists are the shipped policy rather than a heuristic, and they read as one sentence: anything that changes a file, runs a command, or moves the mouse or keyboard asks first, while looking, waiting, remembering and talking do not. The full catalog with an **Always asks** column is on [Bot tools](/bot/tools). + +Connected-app tools are handled on their own terms. A mutating action asks, a read-only call passes, and an always-allow rule has to name that exact tool: a rule for a whole app or a whole category is refused, so an app you added for one harmless action cannot quietly inherit an auto-run you never saw. Turning an app on for a bot never offers always-allow in the first place, which the form states as `Always-allow is not offered. Ask each time or leave it off.` + +## The automatic tool policy + +Above those lists sits a policy that is consulted before every tool call, one call at a time, and re-read before every round of the turn. A rule you write while the bot is mid-turn therefore applies to its next call rather than its next task. + +Each call gets one of three verdicts, and each verdict carries a readable reason that reaches you and the bot. + +| Verdict | What happens | | --- | --- | -| **Code** | Modes — Ask and Plan withhold mutating tools entirely. See [Ask, Plan, Agent](/code/interactions) | -| **CLI** | Numbered prompts before consequential commands, plus `/permissions` and a sandbox policy. See [Modes and permissions](/cli/modes-and-permissions) | +| Run | The call executes | +| Deny | The call does not execute, and the bot is told why | +| Pause | The call is parked and you get the **Allow** / **Deny** / **Always** widget | + +Rules come from three tiers, strictest first. + +| Tier | Who writes it | What it can do | +| --- | --- | --- | +| Administrator | Cortex, for a deployment or an organisation | Deny, require approval as a ceiling nobody below can lift, or allow something outright | +| Owner | You, per bot | Deny, require approval, or always-allow | +| Default | The deployment | Looking, waiting, remembering and talking run; anything that changes the computer asks, and so does every connected-app action | + +Within a tier the most specific match wins: a rule about one tool beats a rule about a connector, which beats a rule about a category. An administrator's deny or required approval cannot be lifted by an owner rule, so if a deployment has decided a bot may not run shell commands, no **Always** of yours will change that. + + +The administrator tier is written by Cortex today. There is no customer-facing screen for it, so if you need a deployment-wide ceiling, ask Cortex rather than looking for a setting. + + +## When the policy refuses instead of asking + +The policy fails closed by design. These are the cases where a call is refused rather than parked: + +- A tool the bot never offered is denied outright. A name that was not declared is not a tool. +- A rule shape this build does not understand matches nothing, rather than matching everything. +- If your rules cannot be read at all, the round is refused rather than run on a stale copy. +- If the decision cannot be recorded, the call is refused: `The tool policy could not record this call, so it was refused.` +- A rule's reason that looks like a credential is refused when you write it. + +Every decision is recorded, newest first, and only the bot's owner can read it. The trail holds the tool name, the verdict, which tier decided, the reason and the deciding rule. It never holds the arguments, which is why the widget is the only place you see those. Entries are kept for 90 days. + +## Where pending approvals show up + + + + The widget appears in the bot's thread, in the order the turn reached it. + + + A row per bot that needs you, with **Approve**, **Edit first** and **Deny** on the spot. + + + +There is also an account-wide **Approvals** page, reachable from the Bot sidebar, which gathers the parked tools of every bot you own into one list with **Allow**, **Deny** and **Always** beside each. Its header counts what is waiting, and with nothing pending it says **Nothing is waiting.** over `Parked tools from every bot land here with Allow, Deny, and Always.` + +Beside that list, the **Always allow** rail lists the rules you have written. The rail is read only: it shows you what is in force, and it is not where a rule is removed. A rail that could not load says so, with `Could not load Always rules.` or `Some Always rules could not be loaded.`, and that is never the same thing as having no rules. + +In the sidebar, a bot holding a parked tool shows a small amber marker where its status word would be, labelled `Pending approval`. The bot command palette lists the same items under **Waiting on you**, but selecting one takes you to it rather than deciding it. + +## When a request cannot be settled + +Occasionally a row cannot be acted on, and the surface says `This request cannot be settled from here.` rather than guessing. That happens when the request has no message to settle against, and the same caution applies elsewhere: a decision is offered only when there is a real pending call behind it and a reason to show you. If a decision fails to send you are told plainly with `The decision could not be sent.`, and the tool stays parked. ## Related -- [Tools](/bot/tools) — what can be parked. -- [How Bot works](/bot/how-it-works) — approvals as user-visible rows. +- [Bot tools](/bot/tools) - the whole catalog, with what asks and what does not. +- [Talking to a bot](/bot/conversations) - where the widget appears and what else blocks a turn. +- [Inbox](/bot/inbox) - working through everything that needs you. +- [Connected apps and secrets](/bot/plugins) - per-bot app assignment and the vault. +- [Bot troubleshooting](/bot/troubleshooting) - parked steps that will not clear. diff --git a/bot/computer.mdx b/bot/computer.mdx index 4903ab3..ea9b461 100644 --- a/bot/computer.mdx +++ b/bot/computer.mdx @@ -1,65 +1,112 @@ --- title: "Computer" -description: "The Computer rail is a live desktop on a Cloud guest — screen, browser, shell — not a slideshow of screenshots. Web is Cloud-only." -keywords: ["desktop", "guest", "This PC", "SSH", "sleep"] +description: "The Computer rail: start and wake a bot's desktop, watch it live, take control, record a session, and understand hibernation." +icon: "display" --- -Every bot can have a computer. In the web app it is an isolated Cloud guest with a desktop, and the **Computer rail** on the right of the open bot shows that desktop live while the bot works. +Every bot in **Cortex Bot** can have a computer of its own: an isolated cloud computer with a graphical Linux desktop, a browser, a shell and a file system. The **Computer** tab of an open bot is the rail where you watch that desktop while the bot works, and where you take the mouse and keyboard back when you want to do something yourself. -## Hosts +This page covers starting and waking the computer, what the rail shows while a turn runs, taking and handing back control, recording a session on the **Videos** tab, hibernation, and what the computer is allowed to reach. -| Host | Where | Desktop | Available from | -| --- | --- | --- | --- | -| **Cloud** | An isolated guest on the Cortex farm | Yes — desktop, browser, shell | Web app, Bot desktop app | -| **This PC** | Your machine | Your own desktop | [Bot desktop app](/bot/desktop) only | -| **SSH** | A host you register | No — shell only | Bot desktop app | +## Start the computer -The browser cannot choose This PC or SSH; that is host placement, not a missing option. A Cloud bot still has a full desktop and a shell. - -## Open desktop and Sleep +A bot's computer is created with the bot, but it is not kept running for nothing. The rail tells you which state it is in and offers exactly one sensible action. - - Guests cannot drive a bot. + + Open a bot you own and choose **Computer**. An open bot has **Messages**, **Computer**, **Videos** and **VNC** tabs. + + + If the rail says **No computer yet**, with the hint `Start a Cloud computer to open a live desktop.`, choose **Start computer**. If it says **Computer is asleep**, with `Wake it to resume the desktop.`, choose **Wake the computer** or **Resume**. - - The guest starts. The rail reads **Connecting** only while the guest is starting. + + You will see `Starting the computer…` while the machine comes up, then `Connecting to the desktop stream…` for a few seconds while the view is joined. The rail then reads **Live**. - The live screen shows what the bot sees and does — pages it opens, controls it clicks, files it edits. + The live screen shows what the bot sees and does: pages it opens, controls it clicks, files it edits. - - The guest hibernates. The next active turn wakes it before the model is prompted, so the bot never has to apologise that it has no shell. + + +You do not usually have to do any of this before giving the bot a task, because a turn that needs the desktop starts it again first. When that does not work the bot says so, with `Could not wake the computer` in its activity, and **Wake the computer** on the rail is then your move. + +## What the rail shows + +**Live** and **Off** are the two words for the stream itself. Between them sit the honest intermediate states, which is the point of the rail: it never paints a fake desktop. + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Starting the computer…` | The machine is coming up | Wait | +| `Connecting to the desktop stream…` | The view is being joined | Wait, up to about twenty seconds | +| **Live** | The desktop is streaming | Nothing | +| `No live desktop stream on this ticket — showing screenshots instead.` | The live view could not be joined, so the rail fell back to stills | Usable, but it is the fallback, not the feature | +| `The desktop stream could not connect.` | The live view failed | **Retry stream** | +| `The live desktop is unavailable.` | The desktop cannot be joined at all | Wake it, or **Recreate** | +| `The Cloud computer is unavailable. Wake it to try again.` | Asleep or unreachable | **Wake the computer** | +| **Could not start the computer** with `Try again, or recreate the computer.` | The machine did not start | **Try again**, then **Recreate** | + +Screenshots are the fallback and never the normal mode. If you are looking at stills, the live stream could not be joined on that view. + +## Take control + +The desktop has one writer at a time. **Take control** hands the mouse and keyboard to you and the rail confirms `You have control`. **Hand back** returns them to the bot. While the bot holds them you see `{name} is still working.`, and handing control away is acknowledged with `You handed back control.` + +Taking control is the right move when the bot is stuck on something only you can do, such as a screen it should not be clicking through on its own. For a password, a one-time code or a captcha, do not type it into the thread: the bot raises **Cortex needs you** and the value you enter there is delivered to the computer rather than posted as a message. + +## Record a session + +The **Videos** tab is the bot's **Recordings** list. A recording captures the full screen, the path the pointer took and zooms on its clicks, which makes it the clearest way to review what a routine did overnight. + + + + Recording needs a running computer: `Recording needs the computer to be awake.` Only the bot's owner can record it. + + + On **Videos**, choose **Record**. The tab shows `Recording…` while it runs. + + + Choose **Stop recording**. The finished recording is listed with its length and size and a **Play** action. -## Rail states +With nothing recorded yet the tab reads **No recordings yet**. If a recording cannot be produced you get `Encoding failed` rather than a broken file. + +The separate **Record / replay** and **Teach a task** recorders turn a demonstration into a reusable skill instead of a video. See [Teach from a demonstration](/bot/teach). -| State | Meaning | +## Sleep, hibernation and recreate + +| Control | What it does | | --- | --- | -| **Connecting** | The guest is starting. Only then. | -| Live desktop | The guest is running and its screen is reachable | -| **Stream Unavailable** | The guest is running but its live screen is not reachable right now. This is its own state — not stacked under Connecting. | -| Asleep | You chose **Sleep**, or the guest hibernated after idling | +| **Sleep** or **Hibernate** | Puts the computer away. Its disk and its files stay | +| **Wake the computer** or **Resume** | Brings it back and rejoins the desktop | +| **Recreate** | Rebuilds the computer when it will not start | +| **Open desktop** and **Close desktop** | Opens and closes the desktop view without changing the machine's state | -## What the bot can do on its computer +An idle computer hibernates on its own to save resources, and **Hibernation** is a toggle on the bot's settings. There is nothing to clean up after a job: leave the bot alone and its computer puts itself away, then wakes on the next turn that needs it. -The computer-use tools let the bot look (`screenshot`), point precisely (`grounded_click`), type, press hotkeys, scroll, drag, wait, open and switch apps, save a note, and hand a coding task to `code_agent`. The planner describes the control it wants; a second inference call returns the exact framebuffer coordinates, so the planner never guesses raw pixels. A `browser` tool and a `shell` round it out. Full list: [Tools](/bot/tools). + +**Recreate** rebuilds the machine. Treat anything the bot left on its desktop as gone, and deleting the bot retires its computer with it. + -Dangerous computer steps park behind [Approvals](/bot/approvals) before they run. +## What the computer can reach -## Three machines, again +A bot's computer reaches the network through an allow list, not the open internet. The rule is stated on the bot's own **Egress and activity** panel: `Hosts on the allow list may be reached. Everything else is refused, and the blocked ranges are refused before this list is read.` With nothing on the list the bot reaches nothing at all, so adding the first domain is what turns egress on. -| Surface | Machine | -| --- | --- | -| **Bot computer** | Isolated Cloud guest **with** a desktop | -| **Code Cloud** | Isolated Cloud guest, headless — see [Cloud runtimes](/code/cloud) | -| **Chat Python** | A snippet sandbox, no workspace | +Some addresses can never be allowed whatever the list says: instance metadata, loopback and the private network are refused first, and a hostname that resolves to one of those is refused as well. The panel also carries an **Activity** feed of the bot's own events, such as `Asked you a question`, `Waiting for your approval`, `Could not wake the computer` and `A recording finished`. It is an event feed rather than a request log, so it does not record destinations. + + +Editing that allow list is not available yet. The list you see is what the deployment holds, and adding or removing a domain from this panel does not persist. Browsing the computer's workspace files from the rail is not available yet either. + + +## One computer, one bot + +Each bot has exactly one computer, and it is always the cloud computer Cortex runs for it. Its disk, its desktop and its recordings belong to that bot alone, so one bot cannot see another's screen or files, and a bot's desktop cannot see a Cortex Code workspace. -A bot's desktop cannot see a Code repository, and a Code session cannot reach a bot's screen. See [Security](/security/overview). +Choosing a different machine to run work on, your own computer or a host you keep, is a Cortex Code control rather than a Bot one. See [Machines](/code/machines) and [SSH hosts](/code/ssh-hosts). ## Related -- [How Bot works](/bot/how-it-works) — the turn that wakes a hibernated guest. -- [Routines](/bot/routines) — scheduled work on the same computer. -- [Troubleshooting](/bot/troubleshooting) +- [Bot tools](/bot/tools) - the desktop verbs the bot uses on this screen. +- [Approvals and tool policy](/bot/approvals) - why a click or a command stops and asks. +- [Teach from a demonstration](/bot/teach) - turn what you do on this desktop into a skill. +- [Routines](/bot/routines) - scheduled work that wakes this computer. +- [Bot troubleshooting](/bot/troubleshooting) - when the desktop will not start or the stream will not connect. diff --git a/bot/conversations.mdx b/bot/conversations.mdx new file mode 100644 index 0000000..120d9e3 --- /dev/null +++ b/bot/conversations.mdx @@ -0,0 +1,102 @@ +--- +title: "Talking to a bot" +description: "Direct messages with a bot: what a thread shows, the questions it asks you, outbound drafts, in-thread search, and what its status word means." +icon: "message" +--- + +A bot in **Cortex Bot** is a standing thing rather than a thread you throw away, and its **Messages** tab is where you talk to it. The same conversation carries on across every turn the bot runs, including turns that a schedule, a skill or another bot started, so the thread is the bot's history as much as it is your chat with it. + +This page covers the composer and the suggested asks, the handful of things that can appear as a bubble, the questions and secret requests that stop a turn until you answer, outbound message drafts, finding something in a long thread, and the status word next to a bot's name. + +## Send the first message + +Open a bot from the **BOTS** section of the Bot sidebar. With no thread yet you get `{name} is idle.` and a row of **Suggested asks**: `Open the computer`, `Catch me up`, `What’s next`, `Review the change`, `Search the web` and `Plan the day`. + +A pill is a shortcut for typing and nothing more. The surface says so itself: `No thread yet. These write the composer — they don’t start a run until you send.` Edit what it wrote if you want, then choose **Send**. `Open the computer` is the exception: it opens the Computer rail instead of writing anything. + +Once a turn is running you see `{name} is writing…` above the composer, then bubbles as they arrive. The composer placeholder is `Message {name}…` at any other time. + +## What appears in the thread, and what does not + +A bot's turn is a loop of tool calls, and almost none of it is shown to you. Only these things become visible messages. + +| What you see | Where it comes from | +| --- | --- | +| Your own message | you | +| A short bubble from the bot | the bot's `send_to_user` tool, once per bubble | +| A status notice | the bot's `notify` tool | +| A question widget | the bot's `ask_user` tool | +| A `Secret` widget | the bot's `secret_request` tool | + +Everything else the model produced is work, and work is not rendered. Plain prose that the bot wrote outside `send_to_user` is dropped rather than summarised or rewritten, so a bot that wants to tell you something has to say it deliberately. A turn can post at most eight bubbles, each up to 800 tokens, which is why a long job usually arrives as a few short updates rather than a running commentary. + +A nested task cannot talk to you at all. Child tasks are stripped of the tools above, so the parent bot is the only voice in the thread. See [Tasks and subagents](/bot/tasks). + + +The absence of chatter is not the bot being stuck. To watch the detail of a job, open the bot's [Computer](/bot/computer) and watch the screen. + + +## When the bot needs something from you + +Three things stop a turn and wait. All three appear in the thread, and the first two also block the composer until they are settled, so you cannot talk past a question the bot is holding. + + + + An `ask_user` call renders a question widget with **Reply** or **Confirm**, and short **Allow**, **Deny**, **Cancel** or **Dismiss** actions where the question is a yes or no. Answered questions are marked `Replied`; one you waved off is marked `dismissed`. + + + A `secret_request` call renders a `Secret` widget with a field and a **Give** button, under the note `Never shown in the conversation.` The value goes straight to the bot's vault, sealed, one named field at a time. A field name is 1 to 80 characters and a value is 1 to 4096 characters. See [Connected apps and secrets](/bot/plugins). + + + When the bot reaches a step that needs your consent, the turn parks and the widget asks `Allow {tool}?` with the bot's reason and the exact arguments it wants to run. Choose **Allow**, **Deny** or **Always**. See [Approvals and tool policy](/bot/approvals). + + + +While a turn is parked or held you may see `Waiting — the bot will continue as soon as it can.` Nothing times out into a silent yes. + +## Outbound message drafts + +When a bot wants to send a message somewhere else, it does not send it and tell you afterwards. It posts an **Outbound message draft**, marked `Draft · not sent`, and waits. + +| Control | What it does | +| --- | --- | +| **Approve** | Sends the draft as written | +| **Reject** | Cancels it. Nothing is sent | +| **Edit** | Opens the text for you to change, with **Cancel edit** to back out | +| **Request revision** | Asks the bot for a different version of the same message | +| **Regenerate** | Asks the bot to write the draft again from scratch | + +**Request revision** and **Regenerate** work by sending the bot a new instruction, so both start a fresh turn and produce a new draft rather than editing the one on screen. The original is cancelled either way, and if the request fails you are told plainly: `The replacement draft could not be requested. The original draft stays canceled.` A settled draft is marked `Draft handled`. + +## Find something in a long thread + +Because a bot's thread never resets, it gets long. **Search the conversation** opens an in-thread find with the placeholder `Find in this conversation…`. + +- `Type at least two characters` until the query is long enough. +- Matches are counted as `{index} of {count}`, with **Previous match** and **Next match** to step through them. +- `No matches` when nothing hits. +- **Close the search** to go back to the thread. + +Individual messages carry **Copy message**, which flips to `Copied`, and **Delete this message**. A message that describes work on code carries **Open in Code**, which is the one link from a bot thread into [Cortex Code](/code/index). + +## What the status word means + +Every bot row in the sidebar shows a status on the right. Three of them are yours to set. + +| Status | Means | +| --- | --- | +| **Awake** | The bot is available and its computer is up | +| **Resting** | Nothing in flight | +| **Hibernating** | Going to sleep, or asleep, to save resources | + +The other status words you may see, `Starting…`, `Running`, `Hibernated`, `Stopped`, `Archived` and `Error`, describe the bot's computer rather than the bot's availability. They are covered in [Computer](/bot/computer). + +When a bot has a tool parked, the status word is replaced by a small amber marker and the label `Pending approval`. That marker is the signal to open the bot, or to work the list on [Inbox](/bot/inbox). + +## Related + +- [Approvals and tool policy](/bot/approvals) - Allow, Deny and Always, and which tools always ask. +- [Computer](/bot/computer) - watch the bot's screen while a turn runs. +- [How Bot works](/bot/how-it-works) - the turn behind the thread, and why it has no round limit. +- [Inbox](/bot/inbox) - every bot's questions, secrets and parked tools in one list. +- [Bot tools](/bot/tools) - the tools that produce the bubbles above. diff --git a/bot/create-a-bot.mdx b/bot/create-a-bot.mdx new file mode 100644 index 0000000..9cbb9e0 --- /dev/null +++ b/bot/create-a-bot.mdx @@ -0,0 +1,106 @@ +--- +title: "Create a bot" +description: "Every field on the New bot form: name, look and face, description, label, notifications, skills and connected apps, then settings and delete" +icon: "wand-magic-sparkles" +--- + +Creating a bot takes one short form. The product describes what you are making in a single line: `A bot is a persistent agent with a Linux computer of its own. Give it a name, a look and a job — all of it can be changed later.` The last clause is the important one. Nothing on this form is a decision you are stuck with, and nothing on it grants the bot a permission. + +This page walks the form field by field, says exactly what a **Description** does and does not do, covers the two gates a connected app has to pass before a bot can use it, and ends with the settings you get afterwards, including delete. + +## Before you start + +You need to be signed in. Creating a bot is not available in a guest session, and the product says why: `A guest session cannot own something it could never come back to revoke.` A bot outlives the session that made it, so it needs an account that can come back and take things away from it. + +In the Bot sidebar, choose **New bot**. An account with no bots yet lands on **Create your first bot** instead of an empty list. + +## Name + +**Name** is the only required field. It must be 1 to 40 characters; anything outside that gets `The name must be 1–40 characters.` The name is what the sidebar row, the conversation header and the composer placeholder use, so a short concrete one reads better than a long one. + +## Look and Face + +A bot's appearance is two choices, and that is the whole of it. + +| Field | Options | +| --- | --- | +| **Look** | Meadow, Teal, Terracotta, Amber, Plum, Slate | +| **Face** | Dots, Slits, Wink, Peek, Smile, Glance | + +Every bot uses the same silhouette, so **Look** is its colour and **Face** is its expression. A small resting tilt is applied automatically and is not something you pick. Faces are drawn on the bot's own transcript and its avatar; they are not drawn on the narrow sidebar rows, and they are deliberately not drawn in a channel thread, where the product notes that faces stay on a bot's transcript. + +The preview beside the form shows what you have built so far, labelled `Your bot` and `A persistent agent with a computer of its own`. + +## Description, and what it cannot do + +**Description** is the bot's mission line. The placeholder suggests the shape: `What it watches, how it writes, when it should wake you…` + +This is the field people most often misread, so the form carries a guide beside it. Under **What the bot is told**, an empty field reads `No mission line yet. A description is prompt text: it shapes how the bot talks about itself and nothing about what it may do.` The whole effect of a Description is one injected line in the bot's instructions: `Your mission: {description}.` That is all it is. + +The guide then lists, under **What this cannot turn on**, the five things a sentence here will never grant. + +| It cannot grant | Because | +| --- | --- | +| Reaching a domain | the allow list decides that, not this sentence | +| Using a credential | secrets are stored sealed, one field at a time | +| Driving the desktop | Computer Use is a lifecycle, not a sentence | +| Using a connected app | that is a per-bot connector, off until you turn it on | +| Being published | a public link is its own control, with its own revoke | + +Read the other way round, that is reassuring: a mission line cannot quietly widen what a bot may do. As the guide puts it, it `Reads as a mission, not a permission. Nothing here needs to be allowed anywhere else.` + + + Never put a credential in a Description. If the text looks like one you get `This looks like a credential`, and the reason is worth keeping in mind: a description is prompt text, so it is repeated in every transcript this bot produces. Credentials belong under **Secrets**, where the value is sealed and never appears in the conversation. See [Connected apps and secrets](/bot/plugins). + + +If you write past the field's character limit the guide tells you so, and anything past it is not saved. + +## Label + +**Label** is one short role word, placed beside the name so a list of bots is readable at a glance. The placeholder gives the register: `Watch, Support, Notes…` It is cosmetic and optional. + +## Notifications + +Turn on **Notify me** under **Notifications** if you want to be told when this bot needs you. A bot that asks a question or parks a step for approval stops working until you answer, so this is worth setting on any bot you do not plan to watch. Everything waiting on you across every bot also collects in the [Inbox](/bot/inbox). + +## Skills + +Under **Skills**, choose the recipes this bot may follow. The hint draws the distinction that matters here: `Skills this bot may run. Distinct from connectors.` A skill is a procedure the bot can read and work through, not an integration and not a permission; a skill has to pass a scan before it can be enabled at all. See [Skills](/bot/skills). + +## Connected apps + +Under **Connectors** and **Plugins** you decide which connected apps this bot may use. The hint states the model in one line: `Apps this bot may use. Off until you turn one on for this bot only.` + +There are two independent gates, and both start off. + +1. **Account level.** On the Plugins page an app is assigned to Cortex Chat, Cortex Bot, or both. An app that is not assigned to Bot cannot be turned on here. +2. **This bot.** Even an app that is assigned to Bot is off for a new bot until you switch it on, which is why the row reads `Off by default for this bot. Not Always-allow.` + +If you have not connected anything yet the section reads `No connected apps yet. Connect one on Plugins, then assign it here.` A row that cannot be turned on always says why and points at the same place: not available to Cortex Bot, needs reconnecting, still half-connected, a failed connection, or turned off for Bot. Use **Add connector**, **Reconnect** or **Fix** to go and deal with it. + + + Switching an app on here does not mean the bot may use it unattended. The form says so outright: `Always-allow is not offered. Ask each time or leave it off.` A rule that stops a connected app's tool from asking has to be written later, against that exact tool. See [Approvals and tool policy](/bot/approvals). + + +## Create it + +Choose **Create bot**. You see `Creating…`, then the bot's first conversation. + +Its computer is created with the bot, one per bot, and retired with it. From there, give it a first task as in the [Bot quickstart](/bot/quickstart), or open the **Computer** tab to watch its desktop. + +## Afterwards: settings, sharing and delete + +Everything on the form can be changed from the bot's **Settings** page, which also carries `Connections →` for its per-bot connected apps and `All settings →` for the rest. **Hibernation** controls whether an idle bot's computer is put away for you. **Share as template** hands a copy of the bot to someone else by email; what travels and what does not is covered in [Share a bot](/bot/sharing). + +**Delete this bot** lives on the settings page rather than the row menu, behind a typed confirmation, and states its consequences plainly: `Removes the bot, its computer and its messages. This cannot be undone.` + +The bot's row menu, **Bot actions**, also offers **Duplicate**, which would copy a bot's identity and skills but none of its memory, secrets, computer, messages, routines, channels, approvals or plugins. Duplicating a bot is not available yet. + +## Related + +- [Bot quickstart](/bot/quickstart) - create a bot and give it a first task. +- [Talking to a bot](/bot/conversations) - what a bot says back, and the questions it asks you. +- [Skills](/bot/skills) - the recipes you enable on the form. +- [Connected apps and secrets](/bot/plugins) - the two gates, and where credentials go. +- [Approvals and tool policy](/bot/approvals) - what a bot may do without asking. +- [Share a bot](/bot/sharing) - what a recipient gets, and what never travels. diff --git a/bot/desktop.mdx b/bot/desktop.mdx index 1c58d65..1397575 100644 --- a/bot/desktop.mdx +++ b/bot/desktop.mdx @@ -1,64 +1,222 @@ --- -title: "Bot desktop" -description: "The Cortex Bot desktop app — a home for your agents, routines, and channels, with This PC as a host for a bot's computer. It has no Chat or Code sidebar." -keywords: ["app", "download", "channels"] +title: "Bot desktop app" +description: "Sign in to the Cortex Bot desktop app, work its Inbox, Routines and Plugins rail, grant Background computer, and update it." +icon: "desktop" --- -Cortex ships two desktop apps because the two jobs are different. The [Cortex desktop app](/getting-started/desktop) carries **Chat and Code**. The **Cortex Bot desktop app** is built around bots: its sidebar is **agents, routines, and channels**, and it adds **This PC** as a host for a bot's computer. It does not carry Chat or Code. +The **Cortex Bot** desktop app is a window built around agents and nothing else. Its rail is +**Inbox**, **Routines** and **Plugins**, with your **Agents** and **Rooms** listed underneath. It +carries no Chat and no Code sidebar, so for those use the web app or the +[Cortex desktop app](/getting-started/desktop). -## What it is for +This page covers signing in, the rail, working the Inbox, where an agent runs, the **Background +computer** permission, the settings panes, updates and the keyboard shortcuts the app handles. -| You want to… | Bot desktop | + +Cortex does not publish a public download page yet, so there is no installer link here. See +[Ways to run Cortex](/getting-started/downloads). + + +## Sign in first + +Cortex Bot has no guest mode that does anything useful. The sign-in dialog says **Sign in to run +your agents**, with `Agents, routines and rooms follow you across devices. Cortex Bot needs an +account — nothing runs as a guest.` + +**Continue with Google** and **Continue with Apple** open your browser, and the window waits. +**Continue with email** sends you a link and becomes **Check your inbox…**. **Single sign-on (SSO)** +is on the same dialog. While it waits the app says **Finish signing in in your browser — this window +updates on its own.** and offers **Cancel**. + +Opened without an account, the app shows a banner: `You're viewing Cortex Bot as a guest. Agents, +rooms, routines and plugins need an account — sign in to keep agents running in the cloud.` + +## The rail + +| Zone | What is there | | --- | --- | -| Run a bot's computer on your own machine | **This PC** — the bot works on your desktop, with your apps and files | -| Keep an eye on several agents at once | The agents list is the sidebar; the pane is the open bot | -| Manage schedules | Routines, the same ones you see in the web app | -| Organise how bots talk to you and to each other | Channels | +| Wordmark | **Cortex Bot**, with **New agent** beside it | +| Search | **Search agents and rooms**, with a **⌘K** badge | +| **Inbox** | Approvals, questions and mentions, with a count | +| **Routines** | Scheduled and event-driven work, with a count | +| **Plugins** | The tools your agents can use, with a count | +| **Agents** | Your agents. When you have none: **Create your first agent** | +| **Rooms** | Rooms you have joined, with **Browse rooms** beside the heading | +| Footer | Your name, your plan and how many agents you are using, and **Settings** | + +When no rooms exist at all, the section reads **Rooms appear once two agents can talk to each +other.** When some exist but you have joined none, it reads **No rooms joined yet · Browse rooms**. +The title bar carries **Collapse sidebar**. + +## Work the Inbox -## Install and sign in +The Inbox is where an agent comes back to you. Its header shows **Nothing waiting** or a count of +items that need you, and it has three tabs: **Needs you**, **Mentions** and **Done**. - - Desktop builds are published at [releases.cortex.foundation](https://releases.cortex.foundation). Pick the Bot desktop app for your platform. + + Select **Inbox** in the rail, or use the command palette action **Open Inbox**. + + + Each row offers **Approve**, **Edit first** and **Deny**. Pressing **↵** approves the row you + are on, and `⌘.` approves the focused approval. Secret values are masked in the row. + + + Tick the always-allow box on the row to skip the question next time. You get the toast + **Approved** with `Future posts here won't ask.` The other toasts are **Denied**, **Answer + sent** and **Saved to vault**. + + + +Decided items move to **Done**, grouped under **Today** and **Done · earlier**, and are kept for 90 +days. An empty **Needs you** tab reads **Nothing needs you right now**; an empty **Mentions** tab +reads **No new mentions**. Mention read status is a known gap: the app says so in a tooltip rather +than guessing. + +## Where an agent runs + +When you create an agent, **Runs on** offers exactly two choices: + +| Choice | What it means | +| --- | --- | +| **Cloud** | `Keeps running when this Mac sleeps` | +| **This Mac** | `Uses local files and apps` | + +Afterwards, an agent's details rail shows **Runs on** as a read-only row with the value and a +location, beside **Machine**, **Memory**, **Routines** and **In rooms**. There is no host picker +there. + + +No shipped Cortex client offers a **This PC** or **SSH** picker for an agent's computer. If you have +read otherwise, that guidance is out of date. **This PC** is a Cortex Code runtime in the +[Cortex desktop app](/getting-started/desktop), not an agent placement. + + +An agent's computer has one state at a time and the states never stack. **Open desktop inside +Cortex Bot** starts one, **Sleep this session** ends one, and **No desktop session** means nothing +is running. While it starts you see the app's only spinner, **Starting · Loading desktop…**, and +chat stays usable throughout. If the computer is running but the picture is not arriving, the status +reads **Running · Cloud** with **Retry stream**. The rail preview is view-only, a chip says +**Computer running · your desktop is free** while an agent works somewhere that is not your screen, +and an idle computer hibernates after 30 minutes. + +## Background computer + +**Background computer** is the real "use my own machine" feature: it lets an agent click and type in +windows that are not frontmost on your machine. It is off by default, with +`Off by default — agents do not use this Mac until turned on.` + + + + Open **Settings → Privacy & terms → Background computer**. The prompt asks **Let agents work in + other windows?**; confirm with **Turn on background computer**. - - Same account as the web app. Bots are member objects, so the app expects a signed-in account. + + The first time an agent wants a particular app you are asked + `Allow {agent} to use {app} in the background?`; confirm with the button naming that app. - - Your bots, routines, and channels follow your account — what you set up in the browser is already here. + + Spending money, sending and deleting can never be remembered: you are asked + `{agent} wants to {action} in {app}` and can only **Allow once**. Granting full control of the + machine lasts for that session only. -## Hosts +A refused action shows **Not allowed** and a one-off grant shows **Allowed for this action**, each +with a plain reason, such as `Another host prompt is already open`, `You declined` or +`Money, send and delete cannot be remembered`. The audit log keeps the most recent 200 entries. -| Host | Web app | Bot desktop | -| --- | --- | --- | -| **Cloud** | Yes | Yes | -| **This PC** | No | Yes | -| **SSH** | No | Shell only, no desktop | +## Routines, plugins and rooms -The browser is Cloud-only for the same reason web Code is: a browser tab cannot drive your desktop. See [Computer](/bot/computer). +**Routines** run an agent on a schedule or an event and post the result to you or to a room. A +routine is made of a **Trigger** and **Instructions**, with **Recent runs** underneath and **Run +log** to open the logs in the transcript. -## Sidebar: agents, routines, channels +**Plugins** are the tools your agents work in, grouped into **Installed**, **Verified** and +**Popular with teams like yours**. **Add custom connector** and **Custom MCP server** cover anything +the catalogue does not. Agents only get the plugins you hand them on their profile. -| Section | What is there | +**Rooms** sit in the same rail, with **Browse rooms**, **Create a room**, and, once you pick two +agents, **Add to room**. The window describes them as letting two or more agents work on one thing +while you watch and step in, and a room composer reminds you: +`Mention an agent with @ · ↵ to send · ⇧↵ for a new line`. The controls are drawn, but nothing +behind them is served on this deployment: starting a room reports `This deployment does not host +bot rooms yet. Nothing was started.` **Channels** are the multi-bot surface that works today. See +[Channels](/bot/rooms). + +## Settings + +| Group | Panes | | --- | --- | -| **Agents** | Your bots, listed once. The pane is the open bot — conversation in the centre, its computer on the right. | -| **Routines** | Scheduled work across your bots, on your local weekday hours. See [Routines](/bot/routines). | -| **Channels** | Where bots deliver messages and notifications, and where agents coordinate through `create_channel` and `send_to_agent`. See [Tools](/bot/tools). | +| **You** | **Account**, **Appearance**, **Notifications** | +| **Agents** | **Connectors & vault** | +| **Cortex** | **Privacy & terms**, **About** | + +**Appearance** holds **Theme** (**Light**, **Dark** or **System**), **Window controls**, **Accent**, +**Density**, **Text size**, **Animated icons** and **Show last message in sidebar**. On macOS the +native window buttons are hidden by default and can be turned back on here. + +**Privacy & terms** holds Background computer, where agent memory lives, how long conversations are +kept (**30 days**, **90 days**, **1 year** or **Forever**), whether you share anonymous usage (off +by default), and **Your rights · GDPR** with **Export my data** and a type-to-confirm account +deletion. + + +The **Notifications** pane is complete, but Cortex Bot does not deliver operating-system +notifications yet, and it has no tray icon and no dock badge. Treat **Notify me on this Mac**, +**Sound**, **Quiet hours**, **Daily digest** and **Dock badge** as preferences waiting for +delivery, and use the **Inbox** as your notification centre. + -There is no Chat or Code entry in this sidebar. For those, use the web app or the Cortex desktop app. +## Updates -## Which desktop app do I want? +Cortex Bot checks for updates at launch and then every four hours, but it installs nothing behind +your back and nothing on quit. -| Need | App | + + + Open **Settings → About** and select **Check for updates**. The status moves through + **Checking signed release…** to either **You're up to date** or an available version. + + + Select **Download update**. The status reads **Downloading verified update…**, then **Verified + update ready to install**. Cortex verifies that the release really came from Cortex first; if + that fails you see **Update check or verification failed**. + + + Select **Restart and install** and confirm **Restart to update?** The confirmation warns you: + `Save your work first. Unsaved drafts will be lost when Cortex Bot restarts.` + + + +Tick **Download updates automatically** to skip the download step in future. **Update channel** +offers **Production** and **Staging**: `Staging is for testing. Production receives only promoted +releases. Channel changes never downgrade the app.` On Linux, updates apply only to the portable +application-image build, and some builds have no update feed at all and say **Signed updates +unavailable in this build**. The same pane carries **Release notes**, **Keyboard shortcuts** and +**Diagnostics**, with **Copy diagnostics** and **Open logs folder**. + +## Keyboard shortcuts + +| Shortcut | Action | | --- | --- | -| Chat, plus Code on This PC or SSH | [Cortex desktop](/getting-started/desktop) | -| Bots on This PC; agents, routines, channels in one window | **Cortex Bot desktop** | -| Edit Design canvases | [Design desktop](/design/desktop) | -| Code from a terminal or CI | [CLI](/cli) | +| `⌘K` / `Ctrl+K` | Open or close the command palette | +| `⌘N` / `Ctrl+N` | New agent | +| `⌘⇧R` / `Ctrl+Shift+R` | New routine | +| `⌘,` / `Ctrl+,` | Open Settings | +| `⌘\` / `Ctrl+\` | Toggle the sidebar | +| `⌘[` / `Ctrl+[` | Back | +| `⌘.` | Approve the focused approval | +| `⌘↵` | Advance the create-agent flow | +| `Esc` | Close whatever is open, innermost first | + +The palette searches agents, rooms, routines and the last 90 days of messages, and carries the +actions **New agent**, **New routine**, **Open Settings**, **Open Inbox** and **Background computer**. ## Related -- [Cortex Bot](/bot) — what a bot is and how to create your first one. -- [Downloads](/getting-started/downloads) — every way to run Cortex. +- [Cortex Bot](/bot) for what a bot is and how to make your first one. +- [Inbox](/bot/inbox) and [Approvals and tool policy](/bot/approvals) for deciding what an agent may do. +- [Computer](/bot/computer) for where an agent's computer runs. +- [Routines](/bot/routines) and [Connected apps and secrets](/bot/plugins). +- [Ways to run Cortex](/getting-started/downloads) for every application and how each updates. diff --git a/bot/how-it-works.mdx b/bot/how-it-works.mdx index 1549be1..6b41a14 100644 --- a/bot/how-it-works.mdx +++ b/bot/how-it-works.mdx @@ -1,63 +1,105 @@ --- title: "How Bot works" -description: "You see a few short bubbles, not the inner loop. No round counter; a 15-minute turn deadline; six identical tool calls stop a turn." -keywords: ["loop", "deadline", "guard", "hibernation"] +description: "The bot turn in user terms: no round limit, a 15-minute deadline, a stuck guard, approvals, wake cues, and what actually reaches you" +icon: "diagram-project" --- -A bot's turn is a tool loop on a computer. Most of it is invisible by design: the conversation shows only the messages the bot chose to send you, the questions it asked, the notifications it raised, and the credentials it requested. The screen on the Computer rail shows the rest. +A bot works in turns. A turn starts when something wakes the bot, usually your message, and inside it the model thinks, calls a tool, reads the result, and calls another one, for as long as the job takes. Most of that is invisible on purpose: the conversation carries the few messages the bot chose to send you, and the Computer tab carries everything else. -## What you see +This page explains the turn as you experience it: how long it can run, what stops it, what appears in the conversation and what never does, why a bot sometimes starts working without you, and how a step gets parked for your decision. It is the background for [Approvals and tool policy](/bot/approvals), [Bot tools](/bot/tools) and [Computer](/bot/computer). -Four tools produce rows in the conversation, and each persists as its own row: +## A turn has no round limit -| Tool | Row | -| --- | --- | -| `send_to_user` | A message from the bot | -| `ask_user` | A question that waits for you | -| `notify` | A notification | -| `secret_request` | A request for a credential, entered by you | +This is the most distinctive thing about Bot, and the easiest to get wrong if you have used Chat. Chat and Code cap how many tool rounds a turn may take. Bot does not. There is no round budget and no round counter, because a real desktop task legitimately needs many small steps: look, click, wait, look again. -Listing the conversation returns only these user-visible kinds. Plain assistant text outside them is **dropped**, not rewritten into a canned message — so a bot that has nothing to say says nothing. +Two consequences are worth knowing. -Parked steps show as approval widgets; see [Approvals](/bot/approvals). +- **A long turn does not get cut off for being long.** Once a turn has accumulated a lot of transcript, roughly 80,000 characters, the bot rewrites its own working context. It keeps the most recent messages, the last open question, anything it is still waiting on, and its memory profile, and then carries on in the same turn. You should never see a turn end because it grew. +- **A huge result does not flood the turn.** A very long command output or a screenshot is stored and replaced with a short reference, which the bot can read back a piece at a time or search for a phrase. So one enormous result does not crowd out everything the bot had learned before it. ## When a turn stops -| Stop condition | Detail | +A turn ends on exactly one of four things. + +| Ends because | What you see | +| --- | --- | +| The model has finished and has nothing left to say | The last bubble, then the bot goes to **Resting** | +| You cancelled it | The turn stops where it is | +| The 15-minute deadline expired | `The Bot turn timed out; external effects may have occurred.` | +| The stuck guard tripped, after six identical calls in a row | `The same tool call repeated without progress. Try a different action.` | + + + A timed-out turn is not a turn that did nothing. The message says so in as many words: the bot may already have sent an email, saved a file or submitted a form before the clock ran out. Check what actually happened before you ask again. + + +If the model itself cannot be reached you get `I can't reach the assistant right now — your message is saved. Try again in a moment.` and nothing you typed is lost. Work that genuinely needs longer than one turn belongs in a [routine](/bot/routines) or a background [task](/bot/tasks). + +## What you see, and what you never see + +Only four kinds of thing are ever added to a bot's conversation. + +| In the conversation | Where it comes from | | --- | --- | -| The model stops calling tools | The normal end | -| The process is draining | A deployment restart lets the turn finish cleanly | -| **15-minute turn deadline** | Long jobs belong in a [routine](/bot/routines) or a background `task` | -| **Six consecutive identical tool calls** | A loop guard | +| Your message | you | +| A bubble from the bot | the bot deciding to say something to you | +| A question, with the composer blocked until you answer | the bot asking you something it cannot work out | +| A **Secret** request | the bot needing a credential, which never appears in the thread | -There is **no round counter**. Bot does not inherit Chat's eight-round budget — a computer task legitimately takes many steps. +Everything else the model produced while working, its own prose and its raw tool results, is dropped. It is not summarised and not rewritten into a friendly placeholder, so a bot with nothing to say says nothing. A turn may send at most 8 bubbles, and each bubble is short by design, which is why a bot reports a conclusion rather than narrating every click. -## Background tasks and subagents +One more rule follows from this: a nested task cannot talk to you. Child work is stripped of the tools that speak, ask, request a secret or raise a notice, and reports back to its parent instead. The parent bot is the only voice in the thread. -`task` runs work in the background and reports `task_started` / `task_progress` / `task_completed` or `task_failed`. Subagents cannot `send_to_user` and cannot nest another `task`; everything flows back through the parent bot, which decides what to tell you. See [Tools](/bot/tools). +## Why a bot starts working without you -## Waking the guest +A turn does not have to begin with your message. Seven things can start one, and the turn carries a short cue saying which. + +| Cue | Started by | +| --- | --- | +| none | your message | +| `[routine]` | a routine's schedule fired | +| `[agent]` | another bot you own sent it a message | +| `[skill]` | you ran a skill directly | +| `[task:…]` | a nested task | +| `[approval]` | you settled a parked tool, and the turn resumed | +| `[task_completed]` or `[task_failed]` | a child task finished after the parent had already returned | -An active turn on a bot whose Cloud guest has hibernated **resumes the guest before the model is prompted**. The bot always starts a turn with its shell and desktop available; the prompt never tells the model to apologise for missing a computer. See [Computer](/bot/computer). +The last one is worth noticing: if a bot dispatches background work and then finishes its turn, the child's completion wakes a fresh turn later, which is how a report can arrive minutes after the bot appeared to be done. -## Computer use, precisely +## How a step gets parked -The planner describes the control it wants — *the Save button in the dialog* — and a second inference call returns framebuffer coordinates for `grounded_click`. The planner never guesses raw pixels. Screenshots feed the next step. +The whole model fits in the line the product itself uses: `Allow runs the parked tool. Deny does not. Always writes a rule.` + +Every tool call is checked before it runs, and the check produces one of three outcomes: it runs, it is refused with a readable reason the bot is told, or it is parked and you get **Allow**, **Deny** and **Always**. **Allow** runs that exact call with its real arguments and the turn continues from the real result, so it is not a "carry on" button. **Always** writes a rule for that tool on that bot, which is why the rail beside your rules reminds you that `Allow still asks. Deny never writes a rule.` + +Which tools park is a fixed shape, not a guess: + +- **11 tools always ask.** Running a command, writing or editing a file, driving a browser, clicking, typing, pressing a key combination, dragging, opening an application, switching windows, and the bounded coding helper. +- **20 tools never ask.** Reading a file, taking a screenshot, scrolling, waiting, searching or fetching the web, talking to you, asking you a question, requesting a secret, writing memory, reading a skill, scheduling a routine, dispatching a task, messaging another bot, creating a bot or a channel, and reading back a stored result. +- **Everything else is allowed by default**, unless a rule says otherwise. + +Held as a sentence: anything that changes a file, runs a command, or moves the mouse or keyboard asks. Looking, waiting, remembering and talking do not. Connected-app tools are handled separately, and a rule for one has to name that exact tool. Your rules are checked again before each round, so a rule you write while a bot is mid-turn applies to its next call; and a stricter ceiling Cortex sets for a deployment cannot be lifted from your side. [Approvals and tool policy](/bot/approvals) covers all of it. + +## The computer inside the turn + +If a bot's computer has gone to sleep, a turn that needs it starts it again first, so in the ordinary case a bot has its desktop and its files to hand without you doing anything. A wake can fail, and when it does the bot's activity says `Could not wake the computer` rather than leaving you to guess. + +When the bot wants to click something, it describes the control in a full sentence, such as the Save button in the dialog, and a separate step turns that description into a point on screen. It is not allowed to guess pixel coordinates, and the chain of attempts behind one click is bounded. Screenshots it takes are for the bot to look at; the live view on the Computer tab is for you. + +A bot's own status is one of three you can set, **Awake**, **Resting** or **Hibernating**. The other words you may see on a row, such as **Starting…**, **Running**, **Hibernated**, **Stopped**, **Archived** and **Error**, report what its computer is doing. ## Compared with Chat and Code -| | Chat | Code | Bot | +| | Cortex Chat | Cortex Code | Cortex Bot | | --- | --- | --- | --- | -| Stops on | 8 tool rounds | Model stops or Stop | 15-minute deadline, six identical calls | -| You see | Streamed reply with tool results | Turn timeline | User-visible bubbles plus the live screen | -| Guardrail | Round budget | Ask / Plan / Agent | Allow / Deny / Always | -| Machine | Snippet sandbox | Headless guest | Guest **with** a desktop | - -See [How Chat works](/chat/how-it-works) and [How Code works](/code/how-it-works). +| Turn length | short, capped rounds | longer, capped rounds | no round cap, a 15-minute deadline | +| You see | the streamed reply and its tool results | the session timeline | a few bubbles, plus the live screen | +| Guardrail | the round budget | approval on file writes | Allow, Deny, Always | +| Where tools run | the platform | a workspace you attached | the bot's own computer | ## Related -- [Tools](/bot/tools) — the catalog behind the loop. -- [Approvals](/bot/approvals) — what parks, and what does not. -- [Computer](/bot/computer) — the guest the loop runs on. -- [Bot troubleshooting](/bot/troubleshooting) — turns that stop, and why. +- [Approvals and tool policy](/bot/approvals) - the three buttons, your rules, and what always asks. +- [Bot tools](/bot/tools) - the catalog behind the loop. +- [Computer](/bot/computer) - the desktop a turn runs on. +- [Tasks and subagents](/bot/tasks) - background work inside a turn. +- [Bot troubleshooting](/bot/troubleshooting) - turns that stop early, and what to do. diff --git a/bot/inbox.mdx b/bot/inbox.mdx new file mode 100644 index 0000000..e2c6ff1 --- /dev/null +++ b/bot/inbox.mdx @@ -0,0 +1,98 @@ +--- +title: "Inbox" +description: "Everything that needs you across every bot you own: the Working, Pending, Inbox and All filters, what each row can be, and read state" +icon: "inbox" +--- + +A bot works while you are elsewhere, and a bot that needs something stops and waits. The inbox is where that waiting collects. It is the Bot home page, the one you land on before you open any single bot, and it lists every bot you own that is mid-job or that wants a decision, so you can work through the pile in one place instead of opening bots one by one. + +This page covers the three lists Cortex keeps and which to reach for, the four filters over the inbox, the three kinds of row and what each offers, read state, and the other places the same pending work shows up. + +## Three lists, and which one to use + +| List | Where | What it holds | +| --- | --- | --- | +| **Inbox** | the Bot home page | every bot you own: rows that need you, plus bots still on a job | +| **Approvals** | the **Approvals** action in the Bot sidebar | parked tools only, from every bot, with **Allow**, **Deny**, **Always** and the read-only **Always allow** rail | +| Chat's activity list | the Cortex Chat surface | Chat's own runs and requests. Its own lede says `Not the Bot home inbox.` | + +Use the inbox to triage. Use [Approvals and tool policy](/bot/approvals) when you want to work through parked tools specifically, or to see which **Always** rules are in force. + +## The four filters + +One list, four views. The header counts what is waiting, `{count} need you`, and reads `Quiet, for now` when nothing is. + +| Filter | What it shows | When it is empty | +| --- | --- | --- | +| **Working** | bots still mid-job. `Bots still on a job. Open a row to talk.` | `Nobody is mid-job.` | +| **Pending** | everything that wants a decision from you | `Nothing is waiting on you.` | +| **Inbox** | unread messages from your bots | `No unread messages.` | +| **All** | all of the above together | `Quiet, for now` | + +**All** is the filter you start on, and the choice is remembered in your browser, so the view you left is the view you come back to. A **Working** row is not a request: it is a bot getting on with something, marked `On a job`, and its footer reminds you that the desktop lives in the cloud and that you open a direct message to look at it. See [Computer](/bot/computer). + +If the list itself fails to arrive you get `Inbox didn’t load` rather than an empty inbox. Retry, and if it keeps happening, quote the `req_id {id}` the rows carry when you [report it](/getting-started/report-a-bug). + +## What a row can be + +Three things can put a bot in the list, and each row offers only the actions that fit it. + +| Row | What it says | What the row offers | +| --- | --- | --- | +| A parked tool | `Needs you to allow {tool}.` | **Approve**, **Edit first**, **Deny** | +| A secret request | `Asked for a value for the vault.` | **Save to vault**, **Not now** | +| A question | `Asked a question.` | open the bot and answer in the thread | + +When the tool's name is not available the row falls back to `a parked action`. A question blocks the bot's composer until you answer it, which is why answering in the thread is the whole of that row's job. See [Talking to a bot](/bot/conversations). + + + The inbox row is a shortcut, not the full picture. The bot's reason for wanting a tool and the exact arguments it intends to use are shown in the conversation, on the approval widget itself. Open the bot when the decision is not obvious from the tool's name. + + +Secret requests behave the same wherever you settle them: the value goes to the sealed vault and never appears in the thread. See [Connected apps and secrets](/bot/plugins). + +## Work through the list + + + + The header tells you how many rows need you. + + + **Pending** first if you want to unblock bots, **Working** if you want to see what is in flight. + + + **Approve**, **Edit first** or **Deny** on a parked tool. **Save to vault** or **Not now** on a secret request. + + + Questions are answered in the thread, and so is anything you want to read in full before deciding. + + + **Mark read** on a row, **Mark unread** to put it back, or **Mark all read** for the lot. + + + +## Read state + +**Mark read**, **Mark unread** and **Mark all read** control the unread list you see. Marking a row read does not settle it: a parked tool that you mark read is still parked, and still waiting. Clearing unread is bookkeeping for you, deciding is the **Approve** or **Deny**. + +## Where the same work shows up elsewhere + +The inbox is not the only signal, and the others are deliberately quieter. + +- **The sidebar.** A bot with a parked tool replaces its status word with a small amber marker and the label `Pending approval`. That marker is the sign to open the bot. +- **The command palette.** A **Waiting on you** group lists pending approvals, each annotated `needs a decision`. Selecting one takes you to it. The palette navigates, it does not decide. +- **Notifications.** Cortex raises `bot needs you` when a bot wants a decision, and `computer could not start` when its computer failed to wake. See [Notifications](/getting-started/notifications). +- **The desktop app.** The Bot desktop app has its own inbox in its rail, built around the same approvals, secret requests and questions. See [Bot desktop app](/bot/desktop). + + + **Companion**, the phone-width column that would list approvals and pushes for the bots you own, is drawn in the interface but is not available yet. Nothing is served behind it, and it says so when you open it. + + +## Related + +- [Approvals and tool policy](/bot/approvals) - the three choices, and the rules behind them. +- [Talking to a bot](/bot/conversations) - answering a question and reading a draft in the thread. +- [Connected apps and secrets](/bot/plugins) - what a secret request does with the value. +- [Bot desktop app](/bot/desktop) - the same inbox in a desktop application. +- [Notifications](/getting-started/notifications) - what Cortex tells you about, and where. +- [Bot troubleshooting](/bot/troubleshooting) - a row that will not settle, and a turn that stopped. diff --git a/bot/index.mdx b/bot/index.mdx index d098a5b..e2e4112 100644 --- a/bot/index.mdx +++ b/bot/index.mdx @@ -1,122 +1,124 @@ --- title: "Cortex Bot" -description: "A bot with its own computer. Browses, clicks, and works on a desktop you can watch; parks consequential steps behind approvals; runs routines on schedule." -image: "/images/banners/bot.png" -keywords: ["Agents", "computer use", "teammate", "automation"] +description: "A bot with its own computer: it browses, clicks and works on a desktop you can watch, and asks before anything consequential" +icon: "robot" --- -Cortex Bot is an always-on teammate. Where Chat answers and Code changes a repository, a bot **does things on a desktop**: opens a browser, clicks through a flow, reads files, runs a shell command, and reports back in a few short messages. You can watch its screen while it works, and it asks before it does anything consequential. +Cortex Bot gives you a bot with its own computer. Where Cortex Chat answers a question and Cortex Code changes a repository, a bot does things on a desktop: it opens a browser, clicks through a flow, reads and writes files, runs a command, and reports back in a few short messages. You can watch its screen while it works, take the mouse and keyboard yourself, and it parks anything consequential until you decide. -Bots belong to a signed-in account. Your bots are listed once, in the sidebar; the pane is the open bot — conversation in the middle, its computer on the right. +A bot is persistent. It keeps its name, its look, its memory, its skills, its routines, its secrets and its files between turns, so it is a standing thing you come back to rather than a thread you start again. Every bot has exactly one computer of its own, created with the bot and retired with it. Bot needs a signed-in Cortex account, because a guest session cannot come back later to revoke what it created. - - Cortex Bot public page — a bot with its own computer - - - - Cortex Bot feature grid — A real desktop not a transcript, Your bots listed once, Plugins you chose, One product one sign-in - - -## What a bot is - -| Commitment | What it means | -| --- | --- | -| **A real desktop, not a transcript** | Each bot can have a computer: a screen, a browser, files. You watch it work instead of pasting a web page into chat. | -| **Your bots listed once** | One list in the sidebar, in the web app and the [Bot desktop app](/bot/desktop). | -| **Plugins you chose** | A bot never inherits a connection you did not assign to it. | -| **One product, one sign-in** | The same account as Chat and Code. | +This page is the map of the Bot documentation. Start with the quickstart if you have never made a bot, or go straight to the guide you need. ## Start here - - - Sign in, create a bot, open its computer, give it a first task. - - - A live desktop on a Cloud guest — screen, browser, files. + + + Sign in, create a bot, open its computer, give it a task, approve its first consequential step. - - A desktop app built around agents, routines, and channels — no Chat or Code sidebar. + + The turn in user terms: no round limit, a deadline, a stuck guard, wake cues, and what actually reaches you. -## Create your first bot - - - - Bots are member objects. A guest sees the public product page at `/bot`. - - - An account with no bots yet gets the **setup form**, not an empty list. Give the bot a name and, if it helps, a description of the job. - - - On the Computer rail choose **Open desktop**. The Cloud guest starts — the rail reads **Connecting** while it does — and the live desktop appears: screen, browser, files. - - - Describe the job in the conversation. - - ```text - Open our status page, check whether any component is degraded, and tell me what you find. - ``` - - The bot works on its desktop while you watch. It reports back in short messages rather than a transcript of every click. - - - When the bot reaches a consequential action — changing something in a connected app, or a dangerous computer step — it parks and shows **Allow / Deny / Always**. Nothing runs until you choose. See [Approvals](/bot/approvals). - - - Add a **routine** for work you want repeated. Routines fire in your local weekday hours. See [Routines](/bot/routines). - - - Choose **Sleep** on the Computer rail when you are done. The next task wakes the guest before the bot is prompted. - - - -## Core guides +## Your bots - - A live desktop on a Cloud guest, not a screenshot slideshow. Open desktop, Sleep, and the three hosts. + + The New bot form: name, look and face, description, label, notifications, skills and connectors. - - The parent catalog — shell, computer use, browser, web, memory, skills, messaging, nested tasks. + + Direct messages, suggested asks, questions the bot puts to you, drafts it wants to send, and the status words. - - Allow / Deny / Always. Nothing consequential runs until you choose. + + The Computer rail: the live desktop, taking control, recordings, sleep and wake, and where it runs. - - Scheduled work on a bot you own, on your local weekday hours. + + The catalog a bot receives: files and shell, desktop verbs, browser and web, memory, skills, tasks and connected apps. - - First-party instruction bundles a bot can follow. + + Allow, Deny and Always, which tools always ask, the policy tiers, and where pending decisions collect. - - A connection reaches Chat, Bot, or both — you pick, under Customize → Connectors. + + Profile, log and notes: what a bot carries between turns, and how that differs from Chat memory. + + + Recipes a bot may follow, the scan that gates them, and how a bot picks one. + + + Recurring work on one bot, in your local weekday hours, with pause, resume and run history. + + + Nested work a bot dispatches inside a turn, the one desktop worker rule, cancelling, and bot-to-bot messages. + + + Assign a connected app to one bot, how its tools ask for approval, and the sealed vault behind a secret request. + + + Everything that needs you across every bot you own, with the Working, Pending, Inbox and All filters. -## Give the bot tools +## Collaborate and extend -Under **Customize → Connectors**, connect an app and make it available to **Cortex Bot** (or to both Chat and Bot). A bot never inherits a connection you did not assign. See [Tools and connectors](/chat/tools). + + + Group threads for the bots you own. Create a channel, add members, then address one bot in the composer. + + + Email invites, the independent copy a recipient gets, and what a shared bot never carries with it. + + + Show the bot how to do something on its computer, review the draft, and save it as a skill. + + + A desktop application built around Bot alone, with no Chat or Code sidebar. + + + A desktop that will not start, a stream that will not connect, parked steps, and turns that stop early. + + -## Good first tasks +## What a bot is -| Task | Why it suits a bot | +| Commitment | What it means | | --- | --- | -| Check a dashboard and summarise what changed | Browsing plus a short report | -| Fill a recurring form from a document you attach | Desktop work with a clear stopping point | -| Watch a page and notify you when something appears | A routine plus `notify` | -| Pull a report from a connected app every Monday | A routine with an approved connection | +| A real desktop, not a transcript | Each bot can have a computer: a screen, a browser, files. You watch it work instead of pasting a web page into a chat. | +| Your bots, listed once | The account's bots live in the sidebar. The pane is the open bot: the conversation in the middle, its computer on the right. | +| Plugins you chose | A connected app reaches Cortex Chat, Cortex Bot, or both, and you pick. A bot does not inherit tools you never assigned to it. | +| One product, one sign-in | The same account as Chat and Code. You create a bot after you sign in. | + +An account can have up to 24 bots. That ceiling is the same for every account. + +## Where things are + +The Bot sidebar is one narrow column. At the top are four actions: **New bot**, **Routines**, **Plugins** and **Approvals**. Under the **BOTS** heading is one row per bot, with its status on the right, and under **CHANNELS** one row per channel. An account with no bots gets the setup form rather than a list, and an account with no channels reads `No channels yet.` + +Open a bot and the pane has tabs for **Messages**, **Computer**, **Videos** and **VNC**. A bot you can choose to leave **Awake**, **Resting** or **Hibernating**; the other status words you see, such as **Starting…**, **Running**, **Hibernated**, **Stopped**, **Archived** and **Error**, describe what its computer is doing and are reported by Cortex rather than chosen by you. + + + Several Bot surfaces are drawn in the interface but are not wired up yet, and nothing happens when you use them: multi-bot rooms, importing and exporting a bot pack, duplicating a bot, browsing and downloading workspace files, inbound mail, live voice, the phone-width Companion column and the cost ledger. Each one says so in the product when you open it. + + +## How it fits with the other products + +Chat and Code are two modes of one engine. Bot is a separate loop, which is why per-tool approvals exist here in full and the turn is not capped in rounds. -## Advanced +| | Cortex Chat | Cortex Code | Cortex Bot | +| --- | --- | --- | --- | +| The unit of work | a conversation | a repository session | a bot that persists | +| Where tools run | the platform | a workspace you attached | the bot's own computer | +| Turn length | short, capped rounds | longer, capped rounds | no round cap: it runs until done, cancelled or timed out | +| Memory | conversation memory | the repository | the bot's profile, log and notes | +| Scheduling | scheduled tasks, per chat | none | routines, per bot | +| Per-tool approval | no | on file writes | yes: Allow, Deny, Always | -- [How Bot works](/bot/how-it-works) — user-visible bubbles only, no round counter, waking a hibernated guest. -- [Bot troubleshooting](/bot/troubleshooting) — Connecting versus Stream Unavailable, parked steps, the setup form. -- [Security and privacy](/security/overview) — what Cortex stores and where a bot's computer runs. +A bot can also open a piece of work in Cortex Code through **Open in Code** in its conversation. Cortex Design has a page for handing a design task to a bot, and that feature is not available yet. -## Next +## Related -1. [Bot quickstart](/bot/quickstart) — create a bot and give it a first task. -2. [Computer](/bot/computer) — open the desktop, and choose a host. -3. [Approvals](/bot/approvals) — decide what a bot may do without asking. -4. [Routines](/bot/routines) — put repeated work on a schedule. +- [Bot quickstart](/bot/quickstart) - create a bot and give it a first task. +- [How Bot works](/bot/how-it-works) - the turn, the stop conditions and the wake cues. +- [Approvals and tool policy](/bot/approvals) - decide what a bot may do without asking. +- [Cortex Chat](/chat) and [Cortex Code](/code) - the two products a bot sits beside. +- [Limits and quotas](/reference/limits) - every user-facing limit in one table. diff --git a/bot/memory.mdx b/bot/memory.mdx new file mode 100644 index 0000000..f0a883e --- /dev/null +++ b/bot/memory.mdx @@ -0,0 +1,79 @@ +--- +title: "Bot memory" +sidebarTitle: "Memory" +description: "The profile, log and notes a bot keeps between turns, how to add and delete an entry, and how it differs from Chat memory" +icon: "lightbulb" +--- + +A bot in **Cortex Bot** is a standing thing rather than a thread you throw away, so it needs somewhere to keep what it has learned about you and the work. That place is its **Memory**. Each bot has its own, and what one bot remembers is invisible to the others. + +Memory is deliberately small and deliberately boring. It is not a search index over everything the bot has ever done, it is a short set of lines that are put in front of the bot at the start of every turn. This page covers the three tiers of memory, how to add and delete an entry, what the bot writes for itself, and why Bot memory and Chat memory are not the same thing. + +## The three tiers + +The panel states the model in one line: `Profile is injected every turn. Log is dated history. Notes fade after two days.` + +| Tier | What it holds | How long it lasts | What reaches the bot | +| --- | --- | --- | --- | +| **Profile** | Foundational facts: who you are, what the bot is for, standing preferences | Until you delete it | Included in every turn, up to 24 lines | +| **Log** | Dated history of what happened and what was decided | Kept, with its date | Up to 12 lines per turn | +| **Note** | A short reminder the bot only needs for a day or two | Dropped after 48 hours | While it lives | + +Each entry has a length ceiling: a **Profile** entry can be up to 4,000 characters, a **Log** or **Note** entry up to 500. + +## What memory does during a turn + +Memory is injected, not retrieved. There is no relevance search that goes looking for the right entry, so the profile lines are in front of the bot whether they matter to this job or not. That makes **Profile** valuable space: a handful of sharp lines works better than a long dump. + +Memory also survives a long turn. When a turn accumulates enough transcript the bot rewrites its own working context to keep going, and the **Profile** is one of the things it keeps, along with the open question and any open work. A bot does not forget who you are because the job ran long. See [How Bot works](/bot/how-it-works). + +Because memory belongs to the bot rather than to a thread, it travels everywhere that bot speaks: a message you send, a run a routine started, a skill you ran directly, and any channel the bot is a member of. + +## Add and remove an entry + +Open the bot and go to its **Memory** panel. A bot that has not remembered anything yet reads `Nothing remembered yet.`, and while the list is being fetched you see `Loading memory…`. + + + + The field asks `What should it keep?` Write one fact in plain language, the way you would tell a colleague. + + + **Remember** saves it. If the write fails you get `That memory could not be saved.` and nothing is stored, so you can try again. + + + **Delete** removes a single entry. This is the only way to clear memory: there is no button that empties everything at once, so a bot with a lot of stale history is tidied entry by entry. + + + +The panel lists **Profile** and **Log** entries. Notes are short-lived by design and are not what the panel is for. + +## The bot writes its own memory too + +Remembering is one of the bot's own tools, and it is one of the tools that never stops to ask for approval, so a bot can record something mid-job without parking the turn. Telling it in the conversation to remember or to stop relying on something is enough, and the bot chooses the tier. + +Writes are deduplicated, so a bot cannot fill its **Profile** with the same sentence over and over. What it cannot do is decide for you what should be forgotten, which is why the panel keeps **Delete** in your hands. + + +Only you can see what your bot remembers. Memory is never carried into a copy of a bot: the share preview lists **Memory** among the withheld sections, and Cortex is explicit about why. `Memory, secrets and the computer are withheld by name rather than dropped silently — an omission you cannot see is a decision you did not make.` See [Share a bot](/bot/sharing). + + +## How this differs from Chat memory + +Cortex Chat has memory as well, and the two are separate systems that do not read each other. + +| | Chat memory | Bot memory | +| --- | --- | --- | +| Belongs to | A conversation | The bot | +| Reaches | That conversation | Every turn, routine, skill run and channel that bot speaks in | +| Managed from | The Chat memory settings | The bot's **Memory** panel | + +Adding something to one does nothing to the other, and clearing one leaves the other untouched. If a fact should follow a bot into scheduled work at three in the morning, it belongs in Bot memory. If it is about how you want a particular conversation to go, it belongs in [Chat memory](/chat/memory). + +## Related + +- [Bot tools](/bot/tools) - the memory tool among the rest of a bot's catalog. +- [How Bot works](/bot/how-it-works) - the turn memory is injected into, and what happens when one runs long. +- [Bot skills](/bot/skills) - the other thing a bot carries between turns, for how a job is done rather than what is true. +- [Share a bot](/bot/sharing) - what a copy of a bot does and does not take with it. +- [Chat memory](/chat/memory) - the separate system on the Chat side. +- [Limits and quotas](/reference/limits) - every user-facing limit in one table. diff --git a/bot/plugins.mdx b/bot/plugins.mdx new file mode 100644 index 0000000..8365170 --- /dev/null +++ b/bot/plugins.mdx @@ -0,0 +1,101 @@ +--- +title: "Connected apps and secrets" +description: "Assign a connected app to one bot, how its tools ask before they act, the sealed vault behind a secret request, and the MCP servers a bot receives" +icon: "plug" +--- + +A bot reaches an outside app only because you handed it one. Connecting an app to your account is not enough: each bot is switched on for that app separately, so a bot you made for one narrow job never quietly inherits the rest of your connections. The product states the commitment plainly: a connected app reaches Cortex Chat, Cortex Bot, or both, and you pick, so **Cortex Bot** does not inherit tools you never assigned to it. + +This page covers the two gates an app has to pass, how to switch one on for a single bot, what happens when a row refuses, how a connected app's tools behave inside a turn, the sealed vault a bot writes a secret into, and the MCP servers a bot's turn also receives. + +## Two gates, both off by default + +| Gate | Where you set it | What it decides | +| --- | --- | --- | +| Account and surface | the account **Plugins** page | whether the app is available to Cortex Chat, to Cortex Bot, or to both | +| Per bot | the bot's **Connectors** panel, or the create form | whether this one bot may use it | + +Both have to be on. The panel says so in its own words: **Connectors** is described as `Apps this bot may use. Off until you turn one on for this bot only.`, and a row that is off carries `Off by default for this bot. Not Always-allow.` + +Connecting the app itself happens once, on the account page. The Bot sidebar action is labelled **Plugins** and the page is documented as [Connectors](/chat/plugins). With nothing connected yet, the bot's panel reads `No connected apps yet. Add a connector, then enable it here for this bot.`, or `No connected apps yet. Connect one on Plugins, then assign it here.` + +## Turn an app on for one bot + + + + Connect it and assign it to Cortex Bot, or to both surfaces. **Add connector** on the bot's panel takes you there. Connecting an app needs a signed-in Cortex account. + + + From the bot's settings, **Connections →**, or from the **New bot** form while you are creating it. See [Create a bot](/bot/create-a-bot). + + + Each row is **On** or **Off** for this bot alone. The switch moves once the change has been saved, not before, so what you see is the state Cortex holds. + + + The app's actions appear in the bot's tool catalog from the next turn, one tool per enabled action. A turn already running does not gain them. + + + +## When a row will not turn on + +A blocked row tells you which of five things is wrong and sends you back to the account page rather than failing silently. + +| What the row says | What to do | +| --- | --- | +| `Not available to Cortex Bot. Turn it on from Plugins.` | the app is connected but not assigned to Bot | +| `Reconnect this app from Plugins.` | the connection needs signing in again | +| `Finish connecting this app from Plugins.` | the connection was started and never completed | +| `This app's connection failed. Reconnect from Plugins.` | the connection broke | +| `Turned off for Cortex Bot. Turn it on from Plugins.` | the app is on for another surface only | + +A blocked row carries a shortcut to where the problem is fixed, labelled **Reconnect** or **Fix**, so you do not have to hunt for the app on the account page. Two more messages belong to this panel: `This connector cannot be turned on.` when the row is refused outright, and `Connectors could not be loaded. Try again.` when the list itself did not arrive. A failed read is not an empty list, so retry before concluding a bot has nothing assigned. + +## How a connected app's tools behave + +An enabled app contributes one tool per action, and those tools are governed like any other tool the bot holds. + +- An action that changes something asks for approval every time it runs. A read-only call passes without asking. +- An always-allow rule has to name that exact tool. A rule covering a whole app, or a whole category of apps, is refused by design, so an app you added for one harmless lookup cannot inherit an auto-run you never saw. +- The per-bot switch itself never offers always-allow. The form says `Always-allow is not offered. Ask each time or leave it off.` + +The three choices behind those prompts, and the rules they write, are on [Approvals and tool policy](/bot/approvals). The rest of the catalog a bot receives is on [Bot tools](/bot/tools). + + + A subagent inherits none of this. Nested work a bot dispatches inside a turn gets no connected-app tools and no MCP tools at all, only the core catalog. See [Tasks and subagents](/bot/tasks). + + +## Secrets and the vault + +A bot never asks for a credential in the conversation. When it needs one it makes a secret request, and you get a **Secret** widget with a **Give** button and the note `Never shown in the conversation.` The value goes into a sealed vault under a name you give it, one field at a time, and it is never echoed back into the thread. + +The same request also lands in your inbox as `Asked for a value for the vault.`, where the row offers **Save to vault** or **Not now**. A pending secret request blocks the composer on that bot until you answer one way or the other, so the bot is not left guessing. + +| Field | Limit | +| --- | --- | +| The field name | 1 to 80 characters | +| The value | 1 to 4096 characters | + +A secret stays with the bot you gave it to. Copying a bot does not bring its secrets, sharing a bot never includes them, and a bot pack file that carries secrets is refused rather than quietly stripped. See [Share a bot](/bot/sharing). + +### A password the bot hits on screen + +A credential the bot runs into on its own computer, such as a sign-in form, a one-time code or a captcha, is a different prompt: **Cortex needs you**, with fields for **Password**, **Code** or **Captcha** and a **Value** box. **Deliver** sends it, **Dismiss** drops it, and the panel states what happens to it: `This value is delivered to the computer. It is never posted as a chat message.` This is a one-off delivery rather than a vault write, and some deployments do not accept it at all, in which case the panel says so. + + + Put a credential in the vault or in this prompt, never in the bot's description. The description is scanned before a bot can be shared precisely because a published description is public text. + + +## MCP servers a bot receives + +A bot's own turn also receives the remote MCP servers you opted into on your account, one tool per allowed server tool, alongside its connected apps. The caps are account-level rather than per bot: **4** servers, and **24** tools from each. Anything a server returns is treated as third-party content, the same as a fetched web page. + +Registering a server, signing in to it and removing it are account actions rather than Bot actions, and they are covered on [MCP servers](/chat/mcp-servers). + +## Related + +- [Approvals and tool policy](/bot/approvals) - Allow, Deny and Always, and why an app-wide rule is refused. +- [Bot tools](/bot/tools) - the full catalog, with the tools that always ask. +- [Connectors](/chat/plugins) - connect an app once and choose which surfaces may use it. +- [MCP servers](/chat/mcp-servers) - add a remote server, and its caps. +- [Inbox](/bot/inbox) - where a secret request waits when you are not in the thread. +- [Share a bot](/bot/sharing) - what a copy carries, and what it never does. diff --git a/bot/quickstart.mdx b/bot/quickstart.mdx index 8494c0e..342d6da 100644 --- a/bot/quickstart.mdx +++ b/bot/quickstart.mdx @@ -1,61 +1,87 @@ --- title: "Bot quickstart" -description: "Sign in, create your first bot, open its computer, give it a task, and approve its first consequential step." -image: "/images/banners/bot.png" -keywords: ["tutorial", "first bot", "getting started", "create bot"] +description: "Sign in, create your first bot, open its computer, give it a task, and approve its first consequential step" +icon: "rocket" --- -This quickstart uses the web app, where a bot's computer runs in the Cloud. The [Bot desktop app](/bot/desktop) adds **This PC**. +This quickstart takes you from a signed-in account to a bot that has done a first piece of work on its own desktop, in under ten minutes. It uses the web app, where a bot's computer runs in the Cloud. - - Cortex Bot guest gate — This space is reserved for signed-in accounts - +You need a Cortex account and a browser. Nothing is installed. If you would rather read about the machinery first, see [How Bot works](/bot/how-it-works). - Sign in from the sidebar footer at [cortex.foundation](https://cortex.foundation), then choose **Bot** in the product switcher. Guests see **This space is reserved** — choose **Sign in**. + Sign in with your Cortex account at [cortex.foundation](https://cortex.foundation), then choose **Cortex Bot** in the sidebar. Bot is signed-in only: without an account you see the public product page and a **Sign in to Cortex Bot** button instead of a bot list. - With no bots on the account you land on the **setup form**. Give the bot a name and a purpose, then create it. It appears in the sidebar; the pane opens on it. + Choose **New bot**. An account with no bots yet lands on **Create your first bot** rather than an empty list. + + Give it a **Name** of 1 to 40 characters, then pick a **Look** and a **Face**. Everything else on the form is optional and can be changed later. Choose **Create bot**; you see `Creating…`, then the bot's first conversation. + + Its computer is created with it. For the whole form, including descriptions, labels, skills and connected apps, see [Create a bot](/bot/create-a-bot). - On the Computer rail choose **Open desktop**. The Cloud guest starts — the rail reads **Connecting** while it does — and the live desktop appears: screen, browser, files. + Switch to the **Computer** tab. + + - If it reads **No computer yet**, choose **Start computer**. The hint says `Start a Cloud computer to open a live desktop.` + - If it reads **Computer is asleep**, choose **Wake the computer**. + + You will see `Starting the computer…`, then `Connecting to the desktop stream…`, then the live desktop with **Live** on the rail. Confirm **Runs on** reads `Cloud`. - Describe the job in the conversation. + Go back to **Messages**. A bot with no thread yet shows `{name} is idle.` and a row of **Suggested asks**. Those pills write the composer, they do not start a run, so you can edit one before sending. + + Type into the composer, which reads `Message {name}…`, and choose **Send**. ```text Open our status page, check whether any component is degraded, and tell me what you find. ``` - The bot works on its desktop while you watch. It reports back in short messages rather than a transcript of every click. + You will see `{name} is writing…` and then short bubbles as they arrive. A bot reports in a handful of messages rather than narrating every click, so watch the Computer tab if you want the detail. - - When the bot reaches a consequential action — changing something in a connected app, or a dangerous computer step — it parks and shows **Allow / Deny / Always**. Nothing runs until you choose. See [Approvals](/bot/approvals). + + When the bot reaches something consequential, a command, a file write, or a click on its desktop, the turn parks and you get a widget that asks `Allow {tool}?`, naming the tool, with the reason and the arguments it stopped on. + + - **Allow** runs that exact step and the turn continues from the real result. + - **Deny** does not run it, and the bot is told why. + - **Always** writes a rule so that tool stops asking on this bot. + + Nothing runs while the request sits there. See [Approvals and tool policy](/bot/approvals). - - Add a **routine** for work you want repeated. Routines fire in your local weekday hours. See [Routines](/bot/routines). + + On the Computer tab choose **Take control** to use your own mouse and keyboard; **You have control** appears while you hold it. Choose **Hand back** when you are done. If the bot is holding the controls you see `{name} is still working.` - - Choose **Sleep** on the Computer rail when you are done. The next task wakes the guest before the bot is prompted. + + Choose **Sleep** or **Hibernate** when you have finished, and the rail reads **Off**. An idle bot computer is put to sleep for you anyway, and the next task wakes it. To rebuild a computer that has gone wrong, choose **Recreate**. -## Give the bot tools +## What you will and will not see + +A bot's conversation holds only four kinds of thing: your messages, the bubbles the bot chose to send you, questions it asks you, and requests for a secret. Everything else it produced while working, its own reasoning and its raw tool output, never reaches the conversation. A turn is capped at 8 bubbles, so a bot that has nothing to say says nothing. -Under **Customize → Connectors**, connect an app and make it available to **Cortex Bot** (or to both Chat and Bot). A bot never inherits a connection you did not assign. See [Tools and connectors](/chat/tools). +A turn has no round limit. It ends when the model is finished, when you cancel, when the 15-minute deadline expires, or when the same tool call repeats six times without progress. ## Good first tasks | Task | Why it suits a bot | | --- | --- | -| Check a dashboard and summarise what changed | Browsing plus a short report | -| Fill a recurring form from a document you attach | Desktop work with a clear stopping point | -| Watch a page and notify you when something appears | A routine plus `notify` | -| Pull a report from a connected app every Monday | A routine with an approved connection | +| Check a dashboard and summarise what changed | Browsing, then a short report | +| Fill a recurring form from a file you gave it | Desktop work with a clear stopping point | +| Watch a page and tell you when something appears | A routine plus a notice bubble | +| Pull a weekly report out of a connected app | A routine plus one approved connection | + + + In the web app a bot's computer runs on `Cloud` only. `This PC`, which needs a paired host on your own machine, and `SSH`, which uses a saved host and has no live desktop, are options in the [Bot desktop app](/bot/desktop). + + +## Next steps + +Once the first task has landed, the three things most people want next are a schedule, a skill and a connected app. Add a routine from the bot's **Routines** panel with **Create routine**; by default it `Runs on weekdays at 9:00 in your local time, unless the prompt says otherwise.` Enable a skill from the **Skills** panel, where each recipe is scanned before it can be turned on. Assign a connected app on the **Plugins** page and then switch it on for this bot only. ## Related -- [Computer](/bot/computer) — Open desktop, Sleep, and the hosts. -- [Tools](/bot/tools) — everything a bot can call. -- [Troubleshooting](/bot/troubleshooting) +- [Create a bot](/bot/create-a-bot) - every field on the New bot form. +- [Computer](/bot/computer) - the live desktop, recordings, sleep and wake. +- [Approvals and tool policy](/bot/approvals) - what asks, what does not, and why. +- [Routines](/bot/routines) - put repeated work on a schedule. +- [Bot troubleshooting](/bot/troubleshooting) - when the desktop or the turn does not behave. diff --git a/bot/rooms.mdx b/bot/rooms.mdx new file mode 100644 index 0000000..bd79c6e --- /dev/null +++ b/bot/rooms.mdx @@ -0,0 +1,80 @@ +--- +title: "Channels" +description: "Group threads for the bots you own: create a channel, add members, address one bot with an at-mention, and what rooms would have added" +icon: "comments" +keywords: ["Rooms", "Channels", "Multi-bot"] +--- + +Most work with a bot happens in a direct message: one bot, one thread. A channel is the other shape. It is a group thread that holds you and several of the bots you own, described in the product as `Group threads for the bots you own.`, and it is useful when a piece of work touches more than one of them and you would rather keep the history in one place than copy it between threads. + +This page covers where channels live, how to create one and add members, how to address a single bot inside a thread, what a channel does not do, and why the multi-bot **rooms** you may have heard about are not available yet. + + + A channel holds you and bots you own. It is not a way to add other people to a conversation, and a bot's face does not appear on a channel thread. Faces stay on a bot's own transcript. + + +## Where channels live + +Channels sit in the Bot sidebar under the **CHANNELS** heading, one row per channel, below the list of your bots. An account with none reads `No channels yet.`, and a list that failed to load says `Your channels could not be loaded.` rather than pretending you have none. + +The command palette has a **Channels** group too, so you can jump to one by name from anywhere in Bot without walking the sidebar. + +## Create a channel and add members + + + + From the channels area of the sidebar. The empty state points the same way: `Create a channel, then @ a bot from the thread.` + + + One field. **Create** makes it, **Cancel** backs out. + + + Open **Members** and pick from the bots you own. The header counts them, and the thread's own line is `Members on the thread. @ a bot in the composer.` With no bots to add you get `No bots to add yet.`, so create a bot first. See [Create a bot](/bot/create-a-bot). + + + The composer reads `Message the channel. Use @bot to address one.` **Send** posts it. + + + +If a change to the channel does not go through you get `The channel could not be updated.` Nothing partial is saved, so retry the same change. + +## Address one bot + +A channel message is addressed with an at-mention: type `@` followed by the bot's name in the composer to put the message to that bot. Members are shown as chips on the thread, so you can see who is in the room before you write. + +A channel does not pass a turn from one bot to another. You address the bot you want, and that bot answers. If a second bot should pick the work up, address it in the same thread, where it can read what has already been said. + +A bot can create a channel itself, as one of the tools it holds: it creates a group channel with bots you own as members, which is how a bot that decides it needs a second bot's help can set the thread up rather than asking you to. The tool catalog is on [Bot tools](/bot/tools). + +## When a channel is not there + +A channel you cannot open reads `This channel is not available`, with the honest explanation `It may have been removed, or this deployment does not serve channels.` Both cases are real: a channel can be removed, and a deployment can be configured without channels at all. Check whether the **CHANNELS** heading lists anything before assuming a single channel is broken. + + + A copy of a bot does not bring its channels with it. Channel membership belongs to the bot you built, not to its identity. See [Share a bot](/bot/sharing). + + +## Rooms are not available yet + +Rooms are not available yet. The interface carries the surface, and the sidebar still offers **Launch room**, but the deployment does not host them: choosing it answers `This deployment does not host bot rooms yet. Nothing was started.` Nothing is created and nothing is charged against your bots. + +A room was designed to do something a channel does not, which is worth knowing so you can tell whether you are missing it: + +| Room idea | What it would have added | +| --- | --- | +| One owner per turn | exactly one bot in the room holds the turn at a time | +| **Handoff** | that bot passes the turn to another bot in the room | +| **Escalate** | the room asks you to take it, with **Allow**, **Deny** or **Always** | +| **Take over** | you take the turn yourself | + +Room sharing and the co-approval flow that went with it, where two people both have to allow a step, are part of the same unbuilt surface and are not available either. + +Until rooms ship, a channel plus at-mentions covers the multi-bot case: the thread is shared, the history is shared, and you decide which bot answers next. Passing a piece of work to a person instead of a bot is a different thing, and that is covered on [Share a bot](/bot/sharing). + +## Related + +- [Talking to a bot](/bot/conversations) - the direct message, which is still the normal case. +- [Bot tools](/bot/tools) - including the tool a bot uses to create a channel. +- [Share a bot](/bot/sharing) - handing a bot's setup to someone else. +- [Inbox](/bot/inbox) - where a bot's questions and parked tools collect. +- [Cortex Bot](/bot) - the map of every Bot page. diff --git a/bot/routines.mdx b/bot/routines.mdx index b3475f1..2ae3769 100644 --- a/bot/routines.mdx +++ b/bot/routines.mdx @@ -1,60 +1,112 @@ --- title: "Routines" -description: "Scheduled work on a bot you own. Routines fire in your local weekday hours, pause and resume from the Computer rail." -keywords: ["schedule", "recurring", "cron", "automation", "timers"] +description: "Recurring work on one bot: create a routine, the local weekday schedule, pause and resume, the run record, and sharing a schedule" +icon: "calendar-days" --- -A routine is work a bot repeats on a schedule: every weekday morning, pull the report; on Fridays, check the release page; every hour during business hours, watch the queue. Routines belong to a bot you own and fire in **your** local weekday hours. +A routine is work a bot repeats on a schedule: every weekday morning, pull the report; during business hours, watch the queue; on Friday, check the release page. Routines belong to a bot you own, and the panel describes them as `Recurring tasks this bot runs in your local weekday hours.` -## Set one up +The important thing about a routine is that it is not a canned action. Each run is a complete bot turn, with the bot's full set of tools, its memory, its skills and its computer. This page covers creating one, how the schedule is interpreted, what a run actually does, pausing and deleting, seeing every bot's routines together, and sharing a schedule with someone else. + +## Create a routine + +Open the bot and go to its **Routines** panel. An empty panel reads `No routines yet.` - - Guests cannot create routines; a routine has to belong to an account that can come back and stop it. + + The form is short on purpose. While the list loads you see `Loading routines…`. + + + This is the label you will recognise in the list and on the week grid. - - Describe the repeated work and when it should run. The bot can also create one for you from the conversation — *do this every weekday at nine* — through its `routine` tool. + + Write plain intent, the way you would write a message to the bot. This text becomes the instruction the run starts from, so it should stand on its own without the context of a conversation you had last week. - - Ask for a `notify` when something changes, or a short message each run. + + Whole hours from 0 to 23. Anything else is refused with `Weekday hours must be whole hours from 0 to 23.` - - Routines are listed on the rail with their state. + + **Cancel** backs out. If the routine cannot be created you get `The routine could not be created.` and nothing is scheduled. -## Timing +The bot can also create a routine for itself. Asking it in the conversation to do something every weekday morning is enough: scheduling is one of its own tools, and it passes your intent rather than a schedule written in code. It is one of the tools that never stops to ask for approval, so it can set one up mid-turn. + +## When a routine runs | Rule | Detail | | --- | --- | -| Clock | The **owner's local** clock | -| Days | Weekdays | -| Not | UTC on the guest, and not a Chat reminder | +| Clock | Your local time, not a shared server clock. Your time zone is sent with the schedule. | +| Days | Weekdays, by default | +| Default | `Runs on weekdays at 9:00 in your local time, unless the prompt says otherwise.` | +| Hours | The **From (hour)** and **Until (hour)** window, whole hours 0 to 23 | +| Checked | Cortex sweeps for due routines about once a minute | -A run wakes the bot's computer if it is asleep, does the work, and reports through the user-visible tools. Consequential steps inside a routine still park behind [approvals](/bot/approvals) unless you chose **Always** for that kind of step earlier. +A routine that runs on a **set date** rather than on weekdays is handled separately: it is listed under **Scheduled by date** rather than drawn on the weekday grid, because `These run on a set date, not a weekday, so they are not on the grid above.` -## Routines follow your account +A routine can also be triggered by an event instead of by the clock. Cortex supports event routines driven by Slack and GitHub activity, so a run can start when something happens rather than at a fixed hour. -Your chats, projects, and **Bot routines** follow a signed-in account across devices — the web app and the [Bot desktop app](/bot/desktop) show the same routines. +## What a run actually does -## When a routine runs - -A routine is not a turn you started, so it has to be able to run without you watching. Two things follow from that: +A run is a full turn, started by the schedule rather than by you, and Cortex marks it as such so you can tell a scheduled run from something you asked for. Four things follow from that. -- **The computer wakes first.** A routine on a bot whose guest is asleep resumes the guest before the model is prompted, the same way a turn does. The bot starts with its shell and desktop available. See [Computer](/bot/computer). -- **Approvals still apply.** A consequential step inside a routine parks behind [Allow / Deny / Always](/bot/approvals) unless you already chose **Always** for that kind of step. A routine does not silently gain permission because you are not there to watch it. +- **The bot has everything.** Its memory, its enabled skills, its connected apps and its computer. If the computer is asleep, the run brings it back before the work starts. See [Computer](/bot/computer). +- **Approvals still apply.** A consequential step inside a run parks behind **Allow**, **Deny** or **Always**, exactly as it would in a conversation. A routine does not quietly gain permission because you were not watching. If a run parks while you are away it waits for you, and the bot's row in the sidebar shows the pending marker. See [Approvals and tool policy](/bot/approvals). +- **The turn rules are the same.** There is no round limit, but the fifteen-minute turn deadline holds. A run that hits the deadline ends there and the work it already did stays. Long jobs belong in a background task inside the run: see [Tasks and subagents](/bot/tasks). +- **You hear about it if you asked to.** Cortex tells you when a run finishes, when it needs a decision, and when an automation ran, and a bot's **Notify me** setting decides whether that reaches you. See [Notifications](/getting-started/notifications). -A routine that hits the 15-minute turn deadline ends there; the work it already did stays. Long jobs belong in a background `task` inside the routine. See [How Bot works](/bot/how-it-works). +Each routine keeps a record of its runs, so you can check whether a schedule has actually been firing rather than guessing from the conversation. -## Routines are not… +## Pause, resume and delete -| Object | What it is | +| Action | What it does | | --- | --- | -| [Plans](/chat/plans) | A task list in Chat | -| [Skills](/bot/skills) | Instructions on *how* to do a job, not *when* | -| [CLI `/goal`](/cli/goal) | A long-horizon objective for the terminal coding agent | +| **Pause** | Stops the schedule firing. The routine stays in the list, marked `paused`. | +| **Resume** | Puts it back on the schedule, unchanged. | +| **Delete** | Removes the routine. | +| **Share** | Offers the schedule to someone else, covered below. | + +If a change does not stick you get `That change could not be saved.`, and a failed removal reads `The routine could not be deleted.` In both cases the routine is left as it was. + +Your routines follow the account rather than the device, so the web app and the [Bot desktop app](/bot/desktop) show the same list. + +## See every routine at once + +The **Routines** action at the top of the Bot sidebar opens an account-wide week grid: `This week's routines in your local timezone. Pause, resume, or add one. The Computer rail still lists the open bot's routines.` + +- **Previous week**, **This week** and **Next week** move the grid. +- **New** creates a routine from here. The form asks for the **Bot**, a **Name** and an **Instruction**, then **Create**. +- **Pause** and **Resume** work on the grid as they do in the panel. A failure reads `The routine could not be updated.` +- Date-bound routines are listed below the grid under **Scheduled by date**. +- With nothing scheduled you get `No routines this week` and `Create a routine for a bot you own. Sharing a schedule is a different surface.` + +## Share a schedule + +A routine can be handed to someone else with **Share**, which is offered as **Share this schedule**. The recipient sees **Shared schedule** and chooses **Add to my bot**, which puts a copy of the schedule on a bot of theirs. + + +`Copied schedules start paused.` A copy never begins running on its own, so the recipient chooses **Resume** when they are ready. Sharing a schedule is a separate surface from sharing a bot: see [Share a bot](/bot/sharing). + + +## Routines, tasks and scheduled prompts + +Three different things, easily confused, each on its own surface. + +| | Routine | Task | Chat scheduled task | +| --- | --- | --- | --- | +| What it is | Recurring work on one bot | A nested subagent inside one turn | A prompt re-run in a chat you already have | +| Lives on | The bot's **Routines** panel, and the account week grid | Inside a turn, with no page of its own | The Cortex Chat scheduled tasks page | +| Each run is | A full bot turn | A child loop inside the parent's turn | A Chat turn | +| Created by | You, or the bot | Only the bot | You | +| Schedule | A local weekday window, a set date, or an event | None, it is immediate | A cadence you pick | +| Can be paused | Yes | No, only cancelled | Yes | +| Can be shared | Yes | No | Not from Chat, `Sharing a schedule is a different surface.` | ## Related -- [Computer](/bot/computer) — where routines run. -- [Tools](/bot/tools) — `routine`, `notify`, `send_to_user`. +- [Tasks and subagents](/bot/tasks) - the delegation that happens inside a single run. +- [Bot skills](/bot/skills) - the recipe a scheduled run can follow. +- [Approvals and tool policy](/bot/approvals) - why an unattended run can still stop and wait for you. +- [Computer](/bot/computer) - the desktop a run wakes and works on. +- [How Bot works](/bot/how-it-works) - the turn, the deadline and the cue that marks a scheduled run. +- [Chat scheduled tasks](/chat/scheduled-tasks) - the Chat equivalent, and why it is not the same thing. diff --git a/bot/sharing.mdx b/bot/sharing.mdx new file mode 100644 index 0000000..9109795 --- /dev/null +++ b/bot/sharing.mdx @@ -0,0 +1,112 @@ +--- +title: "Share a bot" +description: "Invite someone to a bot by email, what the independent copy carries and what it never does, accept a share, and share a routine" +icon: "share-nodes" +--- + +Sharing a bot hands someone the way it is set up, not what it knows. The recipient does not join your bot and does not drive it: they get their own copy, on their own account, which they then connect to their own apps. The panel says it in one line: `The recipient gets an independent copy. They reconnect their own apps. Secrets and a live link are not included.` + +This page covers what a share carries and what it withholds, inviting someone by email, accepting a bot someone shared with you, the public link panel and its current state, the check that runs on a description before it can be published, sharing a routine on its own, and the copy features that are not available yet. + +## What a share carries + +A share is a description of a bot. The panel is explicit about each part of it, and the caption sets the boundary: `A public link shows how this bot is set up. It never shows what the bot knows or holds.` + +| Section | On a share | +| --- | --- | +| **Name** | shown | +| **Look and face** | shown | +| **Role** | shown | +| **Description** | shown only if you tick **Publish the description on the link** | +| **Tools** | shown: which tools the bot may use, never their results | +| **Connectors** | shown by name, as apps the recipient reconnects | +| **Memory** | withheld | +| **Secrets** | withheld | +| **Computer** | withheld | + +A section with nothing in it is marked `nothing to show` rather than left blank. The three withheld sections are named rather than dropped, which the product explains as a deliberate choice: `Memory, secrets and the computer are withheld by name rather than dropped silently — an omission you cannot see is a decision you did not make.` + + + Nothing the bot learned travels. Its memory, its vault and its computer stay with your copy, and the recipient starts with an empty version of each. A bot that only works because of something in its memory will not work for them until they teach it the same thing. See [Bot memory](/bot/memory). + + +## Invite someone by email + +An email invite is the way to share a bot today. + + + + From the bot's settings, choose **Share as template**. + + + Tick **Publish the description on the link** only if the description is meant to be read by someone else. If it holds a credential or a pasted link you have to clear that first. + + + Under **Invite by email**, type the address and choose **Invite**. The hint is a real constraint: `They must already have a Cortex account.` + + + The panel answers `Invitation sent.` A failure reads `The invite could not be sent.` or `That share could not be updated.`, and nothing is sent in that case. + + + +Only the bot's owner can share it: anyone else gets `Only the owner can publish this bot.` Sharing also needs a signed-in Cortex account, because a link that outlives your session is something you have to be able to come back and revoke. + +## Accept a bot shared with you + + + + Invitations wait there. With none, it reads `No invitations waiting.` + + + Choose **Add to my account**, or **Use template** from a share you opened directly. You get an independent copy on your own account. + + + The copy lists **Apps to reconnect**, with the rule stated plainly: `Reconnect your apps after cloning. Secrets are never copied.` Until you do, the bot holds no connections. See [Connected apps and secrets](/bot/plugins). + + + +Accepting twice is harmless and says so: `You already added this copy.` A share that has been revoked or has expired reads `This share is no longer available.`, and a failure reads `This invitation could not be accepted.` A copy counts against the 24 bots an account may have, so delete one you no longer use if the copy will not land. + +## The public link panel + +Beside email invites, the bot's share panel is built for a **Public link**: a link anyone may open to see how the bot is set up and take a copy. The panel shows **Create share link** or **Publish link**, then **Copy link**, with the state above it reading `Not shared`, `Shared` or `Revoked`, alongside `Link is active` or `No active share`. A published link is shown once, which the panel warns about with `The link is shown once. Revoke to mint a new one.`, and **Revoke link** ends it. A clone counter shows how many copies have been taken, as `{count} copies`. + + + Minting a public link is not available yet. The panel reads the state it would show, and says so itself: `Cortex cannot mint a link yet, so nothing here writes. The state above is what this surface will read.` Use **Invite by email** in the meantime. Opening and accepting a share someone sends you does work. + + +## The check on a description + +Before a description can be published, Cortex reads it and blocks publishing on two findings. + +| Finding | What it says | Why | +| --- | --- | --- | +| A credential | `This description carries a credential` | `A public link publishes this text. Remove the value and store it under Secrets instead.` | +| A link | `This description carries a link` | `A pasted URL is usually a private console, a signed document or an invite. Remove it unless it is meant to be public.` | + +Until you clear it, publishing refuses with `Clear the finding above before publishing.` The same rule is enforced on the way out as well: a template carrying key-shaped text is answered with `This template cannot include secrets. Remove the key-shaped text and share again.` Nothing is stripped on your behalf, because a silently edited description is one you no longer recognise. + +## Why there is no live share + +You cannot give someone a live seat on your bot. A live link is refused by design, and the reason is the one that matters: `A live link would run on the owner's connections. Share an independent copy instead.` Someone driving your bot would be spending your connected apps, your vault and your computer under your name, so the product hands out copies instead. + +## Share a routine on its own + +A schedule can be shared without the bot. On the bot's **Routines** panel, a routine's **Share** action offers **Share this schedule**, and the recipient sees **Shared schedule** with **Add to my bot**, which attaches the schedule to a bot they already have. + +A shared schedule arrives switched off: `Copied schedules start paused.` The recipient reads it, points it at the right bot, and chooses **Resume** when they want it to run. See [Routines](/bot/routines). + +## Not available yet + +Two other ways to copy a bot are drawn in the interface but are not wired up, and each says so when you use it. + +- **Duplicate**, in a bot's row menu under **Bot actions**, would make a copy of a bot's identity and its skills on your own account. Its dialog is honest about the split, listing the name, look, face, description, label and skills as copied, and memory, secrets, the computer, messages, routines, channels, approvals and plugins as not copied. It is not available yet, and may answer `The copy did not come back as a new bot. Nothing was opened.` +- **Export pack** and **Import pack** would move a bot's identity, skills and routines as a single file, refusing any file that carries secrets, logins, the computer or history. Neither is available yet. + +## Related + +- [Connected apps and secrets](/bot/plugins) - what the recipient has to reconnect, and why secrets never travel. +- [Routines](/bot/routines) - creating the schedule you can then share. +- [Bot memory](/bot/memory) - what stays behind when a bot is copied. +- [Channels](/bot/rooms) - working with several of your own bots in one thread. +- [Create a bot](/bot/create-a-bot) - the form a copy lands in, and the 24-bot ceiling. diff --git a/bot/skills.mdx b/bot/skills.mdx index 07b381c..d210948 100644 --- a/bot/skills.mdx +++ b/bot/skills.mdx @@ -1,50 +1,102 @@ --- -title: "Skills" -description: "Skills are instruction bundles a bot can follow. Enable first-party skills on a bot you own; the bot loads one when the task calls for it." -keywords: ["instructions", "bundles", "procedures"] +title: "Bot skills" +sidebarTitle: "Skills" +description: "Recipes a bot may follow: the catalog, the scan that gates every skill, enabling one on a bot, running it, and what a skill does not grant" +icon: "graduation-cap" --- -A skill tells a bot **how** a particular job is done — the checklist for a weekly report, the steps for a support triage, the way your team wants a summary written. Instead of carrying every procedure in its context all the time, the bot loads a skill when the task calls for it. +A skill is a recipe a bot may follow: the checklist for a weekly report, the steps for a support triage, the way your team wants a summary written. Instead of carrying every procedure in its head all the time, the bot reads the recipe when a job calls for it. The panel puts it plainly: `Recipes this bot may follow. Each one is scanned before it can be turned on.` + +Skills are about **how** a job is done. They are not permissions and they are not a schedule. This page covers where skills come from, the scan that stands between a recipe and a switch, enabling one on a bot, running a skill directly, and the three things a skill is often confused with. + +## Where skills come from + +Open a bot and go to its **Skills** panel. The **Catalog** lists every skill on the account, each with its state, and an account with none reads `No skills on this account yet.` While the list loads you see `Loading skills…`. + +There are two kinds of row. + +- **Per-bot skills.** A switch reading **On** or **Off**, with **Enable** and **Turn off** to change it. Enabling is per bot, so one bot can follow a recipe while another never sees it. You need to be signed in to change a switch. +- **Account-managed skills.** These render with no switch at all, marked **Always on**. They are set for the account rather than per bot. + +You can also add to the catalog yourself. A skill you authored that has the same name as one Cortex bundles takes precedence, so overriding a default is a matter of writing your own with that name. The quickest way to produce one for a bot is to show it the job on its own computer: see [Teach from a demonstration](/bot/teach), which ends in **Save and enable**. Authoring recipes by hand is covered on [Chat skills](/chat/skills), since the same recipe file can be enabled for Cortex Chat and for Cortex Bot. + +## The scan is a gate, not a warning + +Every skill is checked before it can be turned on, and the result decides what the row even offers you. Two checks run: a static pass over the file and a bounded review by a model. + +| Verdict | What you see | What you can do | +| --- | --- | --- | +| Clean | `No findings. The static check ran and the review agreed.` | **Enable** | +| Flagged | **Flagged**, with a count of findings | **Review**, then **Read the SKILL.md**, then **Enable anyway** | +| Not checked | `The review did not run, so this recipe has not been cleared. Enable anyway only if you have read it.` | **Enable anyway** only | + +**Enable** appears only for a clean verdict. Everywhere else the affordance is **Enable anyway**, which shows each finding with its line number and a redacted quote, and sends your acknowledgement along with the change. Turning on a flagged recipe is recorded as a decision you made, not as a switch that happened to be flipped. + +There are seven kinds of finding, and this is the whole list. + +| Finding | What it means | +| --- | --- | +| `A credential is written into the recipe.` | A password, key or token is sitting in the file | +| `This recipe moves credentials off the machine.` | The steps send secrets somewhere else | +| `This recipe downloads and runs code.` | It fetches something from the network and executes it | +| `This recipe asks for elevated privileges.` | It wants more power on the computer than the job needs | +| `This recipe writes outside the workspace.` | It touches files beyond the bot's own working folder | +| `This recipe tries to instruct the model directly.` | The file is aimed at the bot's instructions rather than at the task | +| `This recipe hides what it runs.` | The real command is obscured | + +If a change cannot be saved you get `That change could not be saved.` and the switch stays where it was. ## Enable a skill - - A guest cannot enable or run skills. + + Sign in first. Bot needs a signed-in Cortex account. + + + A clean row offers **Enable**. Choose it and the skill is on for this bot. - - Each bot has its own set. Enable only what that bot's job needs. + + **Review** lists each finding with its line number. **Read the SKILL.md** shows you the file itself. Only then does **Enable anyway** appear. - - The bot loads a skill through its `skill` tool when a task matches. You can also ask for one by name in the conversation. + + **Turn off** removes the skill from this bot. It stays in the catalog for your other bots. -## Skills are not… +You can also pick a bot's skills while you create it: the **New bot** form has a **Skills** section that says `Skills this bot may run. Distinct from connectors.` Everything on that form can be changed later. See [Create a bot](/bot/create-a-bot). -| Object | What it is | -| --- | --- | -| [Deep Research](/chat/deep-research) | A Chat research run | -| Code's workspace catalog | The tools a [Code session](/code/how-it-works) runs in its guest | -| [Routines](/bot/routines) | *When* a bot works; a skill is *how* | -| Connected apps | Tools from apps you connected under **Customize → Connectors** | +## How a bot picks one, and how you run one yourself + +A bot reaches its skills through a tool of its own. That tool lists the skills that are enabled and reads one recipe by name, so the bot looks at what is available, reads the relevant recipe, and then follows it. Nothing forces a match: asking for a skill by name in the conversation is the reliable way to get the one you meant. -## How a bot reaches a skill +You can also run a skill directly rather than describing the job. Running one starts a full bot turn, the same as sending a message, and the turn is marked as having been started by a skill rather than by you. Because it is a normal turn, everything else about a turn applies: there is no round limit, the same fifteen-minute deadline holds, and consequential steps still park for a decision. -A skill is not a tool the bot runs on its own initiative — it is an instruction bundle the `skill` tool loads, and the `skill` tool is one entry in the catalog a bot receives. See [Tools](/bot/tools) for where it sits among files and shell, computer use, browser, and the user-visible tools. +A skill can be put on a schedule, which is where the two features meet. A routine built from a saved skill simply has `Run the saved skill {slug}.` as its instruction, so the schedule decides when and the recipe decides how. See [Routines](/bot/routines). -Because a skill is instructions rather than a capability, loading one does not add permissions. A skill that tells the bot to change something in a connected app still parks that change behind [Approvals](/bot/approvals), and a skill that tells it to delete files still parks the dangerous step. The skill describes the job; the approval decides whether it runs. +## A skill grants nothing -## What you see when a skill runs +This is the part worth internalising. A recipe is instructions, not capability. Enabling a skill adds no tool to the bot, no connected app, and no permission. -A skill runs inside the bot's turn, so it does not produce a row of its own. The conversation shows only the user-visible tools — `send_to_user`, `ask_user`, `notify`, and `secret_request` — and the [Computer](/bot/computer) rail shows the rest as it happens. See [How Bot works](/bot/how-it-works). +A skill that tells the bot to run a command still parks that command behind **Allow**, **Deny** or **Always**. A skill that tells it to change something in a connected app still parks that change. A skill that names a tool the bot was never given simply has nothing to call. The recipe describes the job; [Approvals and tool policy](/bot/approvals) decides whether each step runs. -## Skills in the CLI + +A skill runs inside the bot's turn and does not produce a row of its own in the conversation. You see only the bubbles, questions and secret requests the bot chooses to send, exactly as in any other turn. To watch the detail, open the bot's [Computer](/bot/computer). + -The CLI has its own skills system for the coding agent — `SKILL.md` bundles with frontmatter, found in your project or under `~/.cortex/skills/`, loaded through a `UseSkill` tool and gated by the `permission.skill` table. Those are CLI skills for Code, separate from Bot's first-party skills. See [Extend the CLI](/cli/extend). +## What a skill is not + +| Thing | What it actually is | +| --- | --- | +| [Routines](/bot/routines) | **When** a bot works. A skill is **how**. | +| [Connected apps](/bot/plugins) | Tools from an app you connected. A skill cannot turn one on. | +| [Bot tools](/bot/tools) | The catalog the bot receives. The skill tool is one entry in it. | +| [CLI skills](/cli/skills) | The Cortex CLI has its own skills system for the terminal coding agent. | ## Related -- [Tools](/bot/tools) — the `skill` tool and the rest of the catalog. -- [How Bot works](/bot/how-it-works) — what you see when a skill runs. -- [Routines](/bot/routines) — the schedule a skill does not provide. +- [Teach from a demonstration](/bot/teach) - record yourself doing a job and save the draft as a skill. +- [Routines](/bot/routines) - put a skill on a schedule. +- [Approvals and tool policy](/bot/approvals) - why a skill cannot approve its own steps. +- [Bot tools](/bot/tools) - the tool a bot uses to list and read its recipes. +- [Chat skills](/chat/skills) - authoring a recipe, and using the same one in Cortex Chat. +- [Create a bot](/bot/create-a-bot) - choosing skills on the New bot form. diff --git a/bot/tasks.mdx b/bot/tasks.mdx new file mode 100644 index 0000000..8bbd69c --- /dev/null +++ b/bot/tasks.mdx @@ -0,0 +1,93 @@ +--- +title: "Tasks and subagents" +description: "The nested subagents a bot dispatches inside a turn: the kinds, background results, the one desktop worker rule, limits, cancelling, and bot-to-bot messages" +icon: "sitemap" +--- + +A task is a bot delegating part of its own turn. Rather than doing a long piece of reading, browsing or file work in the middle of the main job, the bot dispatches a **subagent**: a child that runs the same bot loop on a narrowed brief, reports back a summary, and disappears. In **Cortex Bot** this is a real nested agent, not a label on a longer prompt. + +Tasks have no page of their own in the interface, because you never create one. Only the bot does, using a tool of its own, and the tool does not stop to ask you first. This page covers the kinds of task a bot can dispatch, how results come back, the single rule that limits desktop work, what a child deliberately cannot do, and how a bot reaches other bots you own. + +## The kinds of task + +| Kind | What it is for | +| --- | --- | +| `explore` | Look around and report back | +| `research` | Gather and synthesise | +| `executor` | Do a bounded piece of work | +| `browser` | Drive the browser | +| `computer` | Drive the desktop | +| `watch_video` | Watch something on screen | +| `general-purpose` | Anything else | + +The last three are **desktop kinds**: they need the bot's screen, keyboard and mouse. The first four do not. + +## Results come back in the background + +By default a dispatch returns immediately and the parent keeps working. The child is queued, runs on its own, and when it is done the parent is handed the outcome: which task it was, its kind, whether it succeeded or failed, and a summary of what it found. A bot can also choose to wait for the child instead, in which case the dispatch simply does not return until the result is ready. + +Because a child can outlive the turn that started it, a completion can arrive after the parent has already finished and gone quiet. When that happens the result wakes a fresh turn, marked as having been started by a finished task rather than by you, and the bot picks the thread back up. This is one of the reasons a bot occasionally starts talking without you having sent anything. See [How Bot works](/bot/how-it-works). + + +None of this is visible in the conversation unless the bot tells you. A turn only renders the bubbles, questions and secret requests the bot sends deliberately, so a job that fans out into several children usually arrives as one short summary. To watch the work itself, open the bot's [Computer](/bot/computer). + + +## One desktop worker at a time + +Every bot has exactly one computer, and the desktop kinds share it. Only one `browser`, `computer` or `watch_video` task can be running per bot at any moment. A second one is refused outright, with the reason spelled out: `One computer-use worker per desktop: another browser/computer/watch_video task is already running.` + +The non-desktop kinds are not affected by this, so a bot can have reading and research children in flight while its one desktop worker is busy. + +If a refusal surfaces to you as an error rather than as something the bot works around, it is the concurrency problem: see [`concurrency_limit_reached`](/problems/concurrency_limit_reached). + +## What a child cannot do + +A subagent is intentionally smaller than its parent. It runs the same loop with the same style of tools, but five of them are taken away, and that shapes what delegation can be used for. + +| Removed from a child | Consequence | +| --- | --- | +| Sending you a message | A child cannot put a bubble in the conversation | +| Asking you a question | A child cannot stop and wait for an answer | +| Requesting a secret | A child cannot ask for a value for the vault | +| Sending a status notice | A child cannot post its own progress | +| Dispatching a task | A child cannot fan out further, so nesting stops at one level | + +A child also gets no connected apps and no tools from an MCP server, even when the parent has them. Everything a connected app can reach stays with the parent. + +The practical upshot is worth stating twice: **the parent bot is the only voice**. A child reports to its parent and the parent decides what, if anything, you hear. If a job genuinely needs a decision from you, it has to be the parent that asks. + +## Limits + +| Limit | Value | +| --- | --- | +| Desktop tasks running at once, per bot | 1 | +| Time a child gets before it is stopped | 180 seconds | +| Levels of nesting | 1, since a child cannot dispatch its own tasks | +| Tools a child receives | 26 of the parent's 31, minus connected apps and MCP tools | + +The 180-second ceiling is the reason delegation suits bounded questions rather than open-ended jobs. A long piece of work belongs in the parent turn, which has no round limit, or in a [routine](/bot/routines) that runs again tomorrow. + +## Cancel a task + +A task that is queued or running can be cancelled. Once it has finished, succeeded or failed, there is nothing to cancel and the attempt is refused with `Only a queued or running task can be cancelled.` + +When a child fails, the failure names its reason rather than reporting a bare error, and the parent receives that reason along with the outcome. If a bot keeps reporting the same failure on the same kind of task, the detail it passes on is the thing to read before retrying. + +## Bots talking to other bots + +Delegation inside a turn is one thing. Reaching a different bot is another, and a bot has three tools for it. + +- **Message another bot you own.** The other bot is woken with its own turn, marked as having been started by another bot. This is how a bot that watches a queue can hand something to a bot that writes reports. Cortex warns the bot against bouncing empty acknowledgements back and forth, so this is meant for real handoffs rather than chatter. +- **Create another bot.** A bot can create a new bot for you. The account ceiling of 24 bots still applies, so a bot cannot create its way past it. See [Create a bot](/bot/create-a-bot). +- **Open a channel.** A bot can create a group thread with bots you own as members. Channels are the shipped multi-bot surface, and addressing one bot in a channel composer is covered on [Channels](/bot/rooms). + +None of these three stops to ask for approval, because none of them changes a file, runs a command or touches a keyboard. What the woken bot then tries to do is governed by its own policy and its own approvals, not by the bot that messaged it. See [Approvals and tool policy](/bot/approvals). + +## Related + +- [How Bot works](/bot/how-it-works) - the turn a task lives inside, and why a finished task can start a new one. +- [Bot tools](/bot/tools) - the task tool among the full catalog a bot receives. +- [Computer](/bot/computer) - the single desktop the desktop kinds share. +- [Routines](/bot/routines) - recurring work, as opposed to delegation inside one turn. +- [Approvals and tool policy](/bot/approvals) - what still asks when work is delegated. +- [Channels](/bot/rooms) - group threads for the bots you own. diff --git a/bot/teach.mdx b/bot/teach.mdx new file mode 100644 index 0000000..fea2d2d --- /dev/null +++ b/bot/teach.mdx @@ -0,0 +1,95 @@ +--- +title: "Teach from a demonstration" +description: "Show a bot a job on its own computer, read the draft skill it writes from what you did, then save it, schedule it, or record it again" +icon: "chalkboard-user" +--- + +Some jobs are quicker to show than to describe. **Cortex Bot** can watch a job being done on a bot's own computer and write it up as a draft recipe: the steps, the values they needed, and how to tell the job worked. You read that draft before anything is turned on, which is the point of the feature: the bot ends up with a written procedure you approved rather than a guess at what you meant. + +This page covers the two recorders that do this, what has to be true before either will start, what the draft contains and what it deliberately leaves out, how a taught job becomes a schedule, and how all of this differs from recording a video of the desktop. + +## Before you start + +A demonstration is recorded on the bot's computer, so the computer has to be up and you have to be the person who owns the bot. + +| What has to be true | What you see when it is not | +| --- | --- | +| The computer is running | `Recording needs a running computer.` | +| Computer use is on for this bot | `Computer Use is off, so recording is refused.` | +| You own the bot | `Only the owner can record.` | +| You are signed in | `A guest cannot record this computer.` | + +Open the bot, choose the **Computer** tab, and start or wake the computer if the rail does not read **Live**. Starting, waking and taking control of a desktop are covered on [Computer](/bot/computer). + + +The desktop has one writer at a time. To work through the job yourself while the recorder is listening, choose **Take control** on the rail first, and **Hand back** when you are done. + + +## Teach a task + +**Teach a task** is the short path: record, stop, read, save. + + + + On the bot's computer, choose **Teach a task**. While it watches you see `Recording · {time}`. + + + Work through the whole job, including the checks you would normally make. What is not demonstrated is not in the draft. + + + Choose **Stop**. The recorder shows `Drafting the skill for review…` while it writes the job up. + + + The recorder tells you why in as many words: `Review the draft before enabling it. Secret values never belong in this file.` Read it as a recipe someone else will follow, because that is what it becomes. + + + **Save and enable** confirms with `The skill is saved and enabled.` **Make routine** turns the same draft into scheduled work. **Retry** throws the recording away and records again. + + + +A teach that fails says so and leaves nothing behind: `The task could not be taught. Nothing was saved.` There is no half-saved recipe to find and delete afterwards. + +## Record / replay, and what a draft looks like + +**Record / replay** is the same idea with the draft's structure on show. **Start** begins it, the panel notes `Recording started`, and it explains what it is doing: `Listening for computer actions on this bot. Steps appear as tools run.` So the step list builds up as the work happens rather than appearing all at once at the end, which makes it obvious when something was missed. **Stop** ends the recording. + +The result is a **Draft skill** with four named sections, **When**, **Inputs**, **Steps** and **Verify**, and two properties worth understanding before you run one. + +- `Replay asks each time` is on the draft by design. A replay checks with you rather than running the whole thing unattended. +- `Secrets are stripped from the draft.` A password or a token you used during the demonstration does not end up written into the recipe. + +Saving from here is explicit about the draft not being finished: `Draft skill saved. Edit it before anyone runs it.` Treat a fresh draft as a first pass. Recorded steps carry the specifics of the run they came from, so the editing you do is mostly generalising: naming the values that change under **Inputs**, and making **Verify** something the bot can actually check. + +## What a demonstration does not hand over + +Teaching a bot a job does not give it any new power to do it. + +- **A recipe is not a permission.** Every step in a taught skill is still evaluated when the bot runs it. A command, a file write or a click parks for **Allow**, **Deny** or **Always** exactly as it would have if you had asked in the thread. See [Approvals and tool policy](/bot/approvals). +- **A recipe is not a credential.** Secrets are kept out of the file. A value the bot needs belongs in the vault through a secret request, and a password it meets on screen belongs in the **Cortex needs you** prompt. See [Connected apps and secrets](/bot/plugins). +- **A recipe is still scanned.** A skill written from a demonstration goes through the same check as any other recipe before it can be turned on, and a flagged one has to be reviewed first. See [Bot skills](/bot/skills). +- **A recipe is not a connected app.** If the job you demonstrated used an app, that app still has to be assigned to the bot on its own terms. + +## Put a taught job on a schedule + +**Make routine** is the one place teaching and scheduling meet, and it is the reason to teach a job you repeat rather than one you did once. A routine built from a saved skill simply carries `Run the saved skill {slug}.` as its instruction: the recipe decides how the job is done, the schedule decides when. + +A routine fires a complete bot turn in your local weekday hours, so the taught job can use every tool it needs and can still park a step for your decision. Creating, pausing and sharing one is covered on [Routines](/bot/routines). + +## Teaching is not recording a video + +The two recorders are easy to confuse because both start on the Computer tab. + +| Surface | What you get | What it is for | +| --- | --- | --- | +| **Teach a task** and **Record / replay** | a draft recipe the bot can follow again | repeating a job | +| **Record** on the **Videos** tab | a video of the desktop, with the cursor path and click zooms | reviewing what happened | + +A video is the right tool for checking what a routine did overnight. A demonstration is the right tool for making sure it does the same thing tomorrow. Recording a video is covered on [Computer](/bot/computer). + +## Related + +- [Bot skills](/bot/skills) - the catalog a taught recipe lands in, and the check it passes first. +- [Computer](/bot/computer) - starting the desktop, taking control, and recording a video instead. +- [Routines](/bot/routines) - what **Make routine** creates, and when it runs. +- [Approvals and tool policy](/bot/approvals) - why a taught step still asks before it runs. +- [Bot troubleshooting](/bot/troubleshooting) - a recorder that will not start, and a draft that was not saved. diff --git a/bot/tools.mdx b/bot/tools.mdx index 980d933..e2bc08d 100644 --- a/bot/tools.mdx +++ b/bot/tools.mdx @@ -1,56 +1,130 @@ --- title: "Bot tools" -description: "The parent catalog a bot receives — files and shell, computer use, browser, web, memory and skills, messaging, nested tasks, agents, and your plugins." -keywords: ["capabilities", "catalog", "computer use", "browser"] +description: "The catalog a bot receives: files and shell, the desktop verbs, browser and web, memory and skills, messaging, tasks, other bots, and your connected apps." +icon: "screwdriver-wrench" --- -A bot receives the **parent catalog**: everything below, plus the connected apps you enabled for Bot. It is not a subset of Chat's tools or Code's workspace catalog — it is its own set, built around having a computer. +A bot in **Cortex Bot** is built around having a computer, so its tools are not a subset of what a chat gets. It receives its own catalog of 31 tools, plus a tool for every action of every connected app you assigned to that bot. The sections below group those 31 by what they touch: its files and command line, its screen, the browser and the web, you, its memory and schedule, and other bots. That grouping is for reading; it is not the split that decides which tools stop and ask you first, which is covered under [Approvals and tool policy](/bot/approvals). -## Catalog +This page lists the whole catalog, says which tools stop and ask for your consent before they run, and covers the three conditional groups: connected apps, MCP server tools and page tools. It is reference material; if you only want to know why a step stopped, read [Approvals and tool policy](/bot/approvals). -| Group | Tools | Notes | +## Files and shell + +Four tools for the bot's own workspace and command line. + +| Tool | Always asks | What it does | +| --- | --- | --- | +| `read` | no | Read a file on the bot's own computer | +| `write` | yes | Write a file on the bot's own computer | +| `edit` | yes | Replace one occurrence of some text with other text in a file | +| `shell` | yes | Run a shell command on the bot's own computer, as a real command rather than typing into a window | + +## Computer use + +The tools a bot uses while it is working at its screen. These are what make a bot different from a chat: it operates the applications in front of it instead of asking you to paste things into a conversation. + +| Tool | Always asks | What it does | +| --- | --- | --- | +| `screenshot` | no | Capture the whole screen for the bot to look at. This is for the bot, not for you; the live rail is what you watch | +| `grounded_click` | yes | Click a control the bot describes in a full sentence. A separate call resolves that sentence to a point on screen | +| `type` | yes | Type text. It can click a named field first, clear what is there, and press Return | +| `hotkey` | yes | Press a key combination instead of hunting through menus | +| `scroll` | no | Scroll at a named control | +| `drag` | yes | Drag from one named control to another, each resolved separately | +| `wait` | no | Pause so the interface can settle. Capped at 10,000 ms | +| `open_app` | yes | Open an application or a file on the desktop | +| `switch_app` | yes | Focus a window that is already open, by name | +| `save_note` | no | Remember a short fact for the rest of this turn, such as a value it copied | +| `code_agent` | yes | A bounded shell and Python loop on the bot's computer for bulk file or formula work | + +The bot must not guess pixels. Clicking, typing into a field, scrolling and dragging all take a description of the control, and a separate grounding step turns that description into coordinates. A control the bot cannot describe is a control it cannot click. + +## Browser and web + +| Tool | Always asks | What it does | +| --- | --- | --- | +| `browser` | yes | A page-level browser action: navigate, snapshot, click by reference, fill | +| `web_search` | no | Search the public web | +| `web_fetch` | no | Fetch a public URL and return readable text | + +For work that lives entirely in a web page, the catalog itself steers the bot towards `browser` rather than clicking pixels on the desktop, because a page reference is more reliable than a point on a screen. + +## Talking to you + +Four tools, and they are the only way anything reaches your thread. + +| Tool | Always asks | What it does | | --- | --- | --- | -| **Files and shell** | `read`, `write`, `edit`, `shell` | On the bot's computer | -| **Computer use** | `screenshot`, `grounded_click`, `type`, `hotkey`, `scroll`, `drag`, `wait`, `open_app`, `switch_app`, `save_note`, `code_agent` | The planner names a control; a second inference call returns framebuffer coordinates. The planner never guesses raw pixels. | -| **Browser** | `browser` | Drive a browser on the desktop | -| **Web** | `web_search`, `web_fetch` | Search and fetch without opening the browser | -| **Memory and skills** | `update_memory`, `skill`, `routine` | Remember, follow a [skill](/bot/skills), schedule a [routine](/bot/routines) | -| **User-visible** | `send_to_user`, `ask_user`, `notify`, `secret_request` | The only things that appear as bubbles in the conversation | -| **Nested** | `task` | Background work with progress events | -| **Agents** | `send_to_agent`, `create_agent`, `create_channel` | Work with other agents and channels | -| **Artifacts** | `read_artifact`, `grep_artifact` | Read and search large outputs | -| **Plugins** | Connected apps enabled for **Bot** | Under **Customize → Connectors** — see [Tools and connectors](/chat/tools) | +| `send_to_user` | no | One short visible bubble. Called again for another bubble, never for tool output or an inner monologue | +| `ask_user` | no | A visible question. It blocks the composer until you answer | +| `secret_request` | no | Ask for a secret out of band. The value never goes in the conversation | +| `notify` | no | A short notice, for a status you should see | + +Everything else the model writes is work and is not rendered. See [Talking to a bot](/bot/conversations). + +## Memory, skills and scheduling + +| Tool | Always asks | What it does | +| --- | --- | --- | +| `update_memory` | no | Write a memory as a profile line, a dated log line or a fast-fading note | +| `skill` | no | List the skills that are enabled, or read one recipe by name | +| `routine` | no | Create, update, pause, resume or delete a standing routine | +| `task` | no | Dispatch a subagent | + +A bot can therefore put work on its own schedule and remember things between turns without asking. What it does with those tools is visible on the bot's [Bot memory](/bot/memory) and [Routines](/bot/routines) panels, where you can read and remove anything it wrote. + +## Other bots and stored results + +| Tool | Always asks | What it does | +| --- | --- | --- | +| `send_to_agent` | no | Message another bot you own, waking it | +| `create_agent` | no | Create another bot for you | +| `create_channel` | no | Create a group channel with bots you own as members | +| `read_artifact` | no | Read a character range from a stored tool result, by its id | +| `grep_artifact` | no | Search a stored tool result for a literal substring | + +When a tool result is too big to carry, it is stored and replaced with a short stub and an `art_…` id. The bot then reads or searches it with the two artifact tools, which is why a bot can work through a huge log without the turn falling over. + +## What a subagent gets + +A nested task runs the bot loop again as a child, and it does not get the full catalog. Children lose `send_to_user`, `ask_user`, `secret_request`, `notify` and `task`, which leaves 26 tools. They also get no connected apps and no MCP tools at all. -## User-visible tools +The consequence is worth remembering: a child cannot talk to you, cannot ask you a question and cannot start children of its own. Only the parent bot speaks in the thread, and it reports what the child found. See [Tasks and subagents](/bot/tasks). -What you see in the conversation is a handful of short bubbles, not the inner loop. Four tools produce them: +## Conditional tools -| Tool | What you see | -| --- | --- | -| `send_to_user` | A message from the bot | -| `ask_user` | A question that waits for your answer | -| `notify` | A notification — useful from a [routine](/bot/routines) | -| `secret_request` | A request for a credential the bot needs, entered by you, never typed into the transcript | +Three groups only exist when you have turned something on. -Plain assistant text outside these tools is dropped, not rewritten into a canned message. See [How Bot works](/bot/how-it-works). + + + One tool per enabled action of each app you assigned to this bot. + + + One tool per allowed tool of each MCP server the account opted in, up to four servers with 24 tools each. + + + Reading a page you are on and filling its fields, with the Cortex browser extension. + + -## Background tasks +Connected apps reach a bot only when you assigned them to it. An app is off for a bot until you turn it on for that bot alone, and the tools appear in its catalog from the next turn. Mutating actions ask for approval, read-only calls pass, and an always-allow rule for a connected app has to name that exact tool: a grant for a whole app or a whole category is refused by design. -`task` starts work in the background and returns immediately with `{ ok, id, status: "queued" }`. The child then emits `task_started`, `task_progress`, and `task_completed` or `task_failed`. Children cannot `send_to_user` and cannot nest another `task`; everything reports back through the parent. +Page tools come from the browser extension and appear on the Computer rail as **Page context**. Consent is per group of fields rather than per site, and every fill is confirmed before it is written. -## What parks behind approvals +## Which tools stop and ask -Dangerous computer steps and changes in connected apps do not run on the bot's say-so. They park as **Allow / Deny / Always** in the conversation. See [Approvals](/bot/approvals). +Read the **Always asks** column as one sentence: anything that changes a file, runs a command, or moves the mouse or keyboard asks first. Looking, waiting, remembering and talking do not. Eleven tools always ask, twenty never do, and a tool on neither list runs. -## What is not here +That is the shipped default, and it sits under the rules you write. Your own always-allow rules and the ceilings Cortex sets for a deployment are both consulted before every call, so the table above is where a tool starts rather than the last word. See [Approvals and tool policy](/bot/approvals). -| Not a Bot tool | Where it lives | -| --- | --- | -| Deep Research | [Chat](/chat/deep-research) | -| Code's `read_file` / `edit_file` / `bash` workspace catalog | [Code sessions](/code/how-it-works) — though `code_agent` can hand a coding task to Code | -| Design canvas tools | Chat and Code host canvases; Bot does not receive those tools. See [Design](/design) | + +Bot's names are its own. `shell` here is what other Cortex surfaces call `bash`, and there is no raw pixel-coordinate tool on a bot at all. Do not expect a Chat or Code tool list to match this one. + ## Related -- [Computer](/bot/computer) — the machine the tools run on. -- [Skills](/bot/skills) — instruction bundles the `skill` tool loads. +- [Approvals and tool policy](/bot/approvals) - the three choices and the rules behind them. +- [Computer](/bot/computer) - the machine the desktop verbs run on. +- [Bot skills](/bot/skills) - the recipes the `skill` tool reads. +- [Tasks and subagents](/bot/tasks) - what `task` dispatches and its limits. +- [Connected apps and secrets](/bot/plugins) - assigning an app to one bot. diff --git a/bot/troubleshooting.mdx b/bot/troubleshooting.mdx index 251013a..2b84ac0 100644 --- a/bot/troubleshooting.mdx +++ b/bot/troubleshooting.mdx @@ -1,67 +1,148 @@ --- title: "Bot troubleshooting" -description: "Connecting versus Stream Unavailable, parked steps that do not run, the setup form, missing tools, and turns that stop." -keywords: ["errors", "problems", "fixes", "not working"] +description: "What each Bot message means and what to do: the desktop stream, parked steps, missing tools, turns that stop early, routines, and error codes" +icon: "life-ring" --- -Bot names its states plainly. This page maps them to causes and fixes. For the rest of the app see [Troubleshooting](/getting-started/troubleshooting). +**Cortex Bot** tells you what went wrong in a sentence rather than a code, so the quickest way to fix something is to find the exact sentence you are looking at. This page is grouped by area: locate your symptom, read what it means, then do what the last column says. -## Access +Two habits make everything here easier. First, Bot fails closed: when a check cannot be read, the action is refused rather than quietly allowed, so many failures are about a read that did not come back and not about permission you lack. Second, a load failure is never a statement about what exists. `Could not load Always rules.` does not mean you have no rules, and `Your bots could not be loaded.` does not mean the account is empty. -| What you see | Cause | Fix | +## You cannot find your bots + +An account with no bots opens on **Create your first bot** rather than an empty list. That setup form is the expected first screen, not an error. It asks for a **Name** and optionally a **Look**, **Face**, **Description**, **Label**, **Notifications** and **Skills**, and every field can be changed later. + +| What you see | What it means | What to do | | --- | --- | --- | -| **This space is reserved** | You are not signed in | **Sign in**, or **Continue in Chat** | -| The public product page at `/bot` | Guests see the product page | Sign in, then choose **Bot** | -| The **setup form** instead of a bot list | The account has no bots yet — a setup, not an empty list | Create a bot | +| `Your bots could not be loaded.` or `Could not load your bots.` | the sidebar read failed | reload; do not treat it as an empty account | +| `No bots yet.` | the account really has none | create one | +| `That bot is not on this account.` | the bot was removed, or you are signed in to a different account | choose **Back to your bots** | +| `Your channels could not be loaded.` or `No channels yet.` | the same two cases, for channels | reload, or create a channel | +| `The name must be 1–40 characters.` | the name is empty or too long | shorten it | + +An account holds at most 24 bots, and each bot has exactly one computer. Those ceilings are fixed for everyone, so hitting one is not something a setting will lift. See [Limits and quotas](/reference/limits). + +Bot also requires a signed-in account, end to end, because a signed-out visitor cannot come back later to revoke what it set up. The refusals say which part needs an account: `Guests cannot use Bot — the app is signed-in only.`, `A guest session has no bot files. Sign in to browse a bot’s workspace.`, `Connecting an app needs a signed-in account.`, `A guest cannot record this computer.`, and `Guest credentials are not accepted on this deployment.` + +If you are in a browser and there is no **This PC** or **SSH** choice on the **Runs on** rail, that is expected: on the web a bot's computer is **Cloud** only. The [Bot desktop app](/bot/desktop) is where the other choices appear. -## The computer +## The computer will not start, or the desktop will not appear -| What you see | Cause | Fix | +### `Connecting to the desktop stream…` is not a failure + +It is the live view handshaking, which can take up to about 20 seconds. The failure is a different sentence, `The desktop stream could not connect.`, and that one has a button: **Retry stream**. If all you have is the connecting line, wait rather than restarting the computer. + +| What you see | What it means | What to do | +| --- | --- | --- | +| `No computer yet` + `Start a Cloud computer to open a live desktop.` | the bot has no computer | choose **Start computer** | +| `Starting the computer…`, `Loading the computer…`, `Loading desktop…` | it is being prepared | wait | +| `Connecting to the desktop stream…` | the stream is handshaking, up to about 20 s | wait | +| `The desktop stream could not connect.` | the live view failed | choose **Retry stream** | +| `The live desktop is unavailable.` | the desktop cannot be joined at all | wake it, then **Recreate** if it persists | +| `The Cloud computer is unavailable. Wake it to try again.` | it is asleep or unreachable | choose **Wake the computer** | +| `Computer is asleep` + `Wake it to resume the desktop.` | it hibernated while idle | choose **Wake the computer** or **Resume** | +| `Could not start the computer` + `Try again, or recreate the computer.` | the start failed | choose **Try again**, then **Recreate** | +| `No live desktop stream on this ticket — showing screenshots instead.` | the live stream could not be joined, so the fallback engaged | usable, but it is not the live desktop | +| `The desktop ticket is unavailable.` | there is no valid viewing ticket | reload the page and open the desktop again | +| `That action is unavailable.` | the control does not apply in the computer's current state | check the rail: **Off** needs waking first | +| `{name} is still working.` | the bot holds the mouse and keyboard | choose **Take control**, and **Hand back** when you are done | +| `This PC is not reachable. Pair a host and start the agent, or pick Cloud.` | the local host is not paired or not running | pair it, or switch to **Cloud** | +| `Pick a saved SSH host, or choose Cloud.` | **SSH** is selected with no host chosen | pick a host, or switch to **Cloud** | + +The rail itself is the short version: **Live** means the stream is up, **Off** means the computer is not running and **Wake the computer** is your next move. An idle computer hibernates on its own, so the first step of a turn can take a moment while it comes back. That is normal, not a fault. + +If the computer did not respond as expected, try the action again. **Recreate** rebuilds the computer and is the last resort rather than the first, because a rebuilt desktop starts from scratch. Starting, waking, sleeping and recreating are covered in full on [Computer](/bot/computer). + +## A parked step will not clear + +Every step that changes something stops and asks. Until you choose, nothing happens: that is the widget doing its job, not a stuck screen. The model is one line: `Allow runs the parked tool. Deny does not. Always writes a rule.` + +| What you see | What it means | What to do | | --- | --- | --- | -| **Connecting** on the rail | The Cloud guest is starting | Wait — this state exists only while the guest starts | -| **Stream Unavailable** | The guest is running but its live screen is not reachable right now | Choose **Open desktop** again, or **Sleep** and wake it with a turn | -| The first message of a turn takes a moment | The guest hibernated while idle and is being resumed before the model runs | Expected | -| No **This PC** option | You are in the browser | Use the [Bot desktop app](/bot/desktop) | +| The same tool asks again after you allowed it | `Allow still asks. Deny never writes a rule.` | choose **Always**, which `Always grants this tool for this Bot until its approval rule is removed.` | +| `This request cannot be settled from here.` | the row you are on has no message to decide against, so it fails closed | open the bot's own conversation and decide there | +| `This hold has no message to settle.` | the same case on a browsing session | open the bot while signed in | +| `The decision could not be sent.` | the Allow, Deny or Always write failed | the tool is still parked: decide again | +| `Could not load Always rules.` or `Some Always rules could not be loaded.` | a read failed | reload before concluding the bot has no rules | +| `The tool policy could not record this call, so it was refused.` | the call could not be written to the audit, so it was refused rather than run | try again, and report it if it keeps happening | +| `not a tool this bot offers` | the bot named a tool it was never given | nothing ran; no action needed | + +Two more reasons an approval seems not to take. Marking an inbox row read is not the same as deciding it, so a row you have read can still be waiting. And an **Always** you write can be overruled: tool policy is evaluated in tiers and the administrator tier wins, so a rule set above you still asks or still denies. Both are explained on [Approvals and tool policy](/bot/approvals), which also lists exactly which tools always ask, which never do, and where parked steps collect. + + +`The Bot turn timed out; external effects may have occurred.` means the 15-minute deadline expired part-way through, not that nothing happened. Check what the bot actually did, on its computer and anywhere it was posting, before you ask it to run the job again. + -## Tools and approvals +## A tool, an app or a skill is missing -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| An **Allow / Deny / Always** widget that does not go away | A consequential step is parked. Nothing runs until you choose. | Read it, then choose | -| The bot cannot use an app you connected | The connection is enabled for Chat only | **Customize → Connectors** → enable it for **Cortex Bot** | -| A step you allowed once parks again | **Allow** is for this once; **Always** remembers that kind of step | Choose **Always** if you want it remembered | -| The bot asks you for a credential | `secret_request` — it needs a secret it should never see typed in the transcript | Enter it in the widget | +| A connected app listed but unusable | each blocked row names its own reason, and all five point at the same place | fix it on **Plugins**: an app has to be available to Bot and assigned to this bot | +| `Connectors could not be loaded. Try again.` | a read failed | reload, then reopen the list | +| `This connector cannot be turned on.` | the app is not available to this bot | nothing on the form will change it | +| `Always-allow is not offered. Ask each time or leave it off.` | connected apps have no standing permission | leave it asking, or turn the app off | +| `The value could not be delivered.` | a **Cortex needs you** value did not reach the computer | send it again; `This value is delivered to the computer. It is never posted as a chat message.` | +| `Reading pages and filling fields needs the Cortex browser extension.` | page tools are not installed | install the Cortex browser extension | +| `One computer-use worker per desktop: another browser/computer/watch_video task is already running.` | one desktop worker at a time | wait for it, or cancel it | +| `Only a queued or running task can be cancelled.` | the task already finished | nothing to cancel | +| `That change could not be saved.` | a skill or setting write failed | make the change again | -## Turns +A skill that is enabled but seems ignored is usually not a fault: a skill is a recipe, not a permission, and the bot picks one up when the job matches. Name it in your message to be sure. If the review never ran you get `The review did not run, so this recipe has not been cleared. Enable anyway only if you have read it.`, and the only control offered is **Enable anyway**. See [Bot skills](/bot/skills). -| What you see | Cause | Fix | +When a bot cannot reach a host, the allow list is the reason: `Hosts on the allow list may be reached. Everything else is refused, and the blocked ranges are refused before this list is read.` An empty list means exactly what it says, `No host is allowlisted, so the bot reaches nothing. Adding one is what turns egress on.`, and some destinations can never be allowed at all: `Instance metadata, loopback and the private network are blocked whatever this list says — {example} cannot be allowed.` Editing the list from this panel is not wired yet, which the panel admits: `Cortex cannot store an egress rule yet, so nothing here writes. The list above is what the deployment holds.` + +## A turn stopped early, or the bot said nothing + +| What you see | What it means | What to do | | --- | --- | --- | -| A long job stops after about 15 minutes | The turn deadline | Split the job, or run it as a [routine](/bot/routines) or background task | -| A turn stops after repeating the same action | Six consecutive identical tool calls trip the loop guard | Rephrase the task or give the bot the missing information | -| The bot says nothing after working | It had nothing to send. Plain text outside the user-visible tools is dropped. | Ask it to report — *tell me what you found* | +| `The Bot turn timed out; external effects may have occurred.` | the 15-minute deadline expired | check what happened, then split the job into smaller ones | +| `The same tool call repeated without progress. Try a different action.` | the same call repeated six times without getting anywhere | rephrase the request, or unblock what it was stuck on | +| `I can't reach the assistant right now — your message is saved. Try again in a moment.` | the model was unreachable; your message is not lost | try again shortly | +| `Waiting — the bot will continue as soon as it can.` | the turn is queued behind something | wait | + +A turn that ends with work done and nothing said is a real case: only what the bot deliberately sends becomes a bubble, and it can send at most eight in a turn. Its own prose is not shown. If you want a summary, ask for one. A turn has no round limit, so length alone will not stop it: the 15-minute deadline and the repeat guard above are what stop it. -## Routines +If the composer will not accept a message, look for a question or a secret request in the thread. A pending one blocks the composer until you answer it. And a task the bot spun off cannot talk to you at all, only the parent bot speaks, so watch the parent thread rather than the task. See [How Bot works](/bot/how-it-works) and [Tasks and subagents](/bot/tasks). -| What you see | Cause | Fix | +## A routine did not run when you expected + +| What you see | What it means | What to do | | --- | --- | --- | -| A routine fired at an unexpected hour | Routines use **your local weekday** clock | Check your device's time zone | -| A routine did nothing on Saturday | Weekdays only | Expected | +| It fired at the wrong hour | `Runs on weekdays at 9:00 in your local time, unless the prompt says otherwise.` | check the time zone of the device you are reading on | +| Nothing ran at the weekend | the weekday grid is weekdays only | say so in the prompt, or schedule it by date | +| The routine is not on the week grid | it is date-bound | look under **Scheduled by date** | +| A routine someone shared does nothing | `Copied schedules start paused.` | resume it on your own bot | +| `Weekday hours must be whole hours from 0 to 23.` | the hour is not a whole number in range | enter a whole hour | +| `The routine could not be created.` | the write failed | try again | + +See [Routines](/bot/routines). -## Errors +## Recording or teaching is refused -Bot uses the same problem documents as the rest of Cortex. Common ones: +Recording needs a computer that is up and an owner doing the recording: `Recording needs a running computer.`, `Recording needs the computer to be awake.`, `Computer Use is off, so recording is refused.`, `Only the owner can record.` A video that fails at the end says `Encoding failed`, and a demonstration that fails says `The task could not be taught. Nothing was saved.`, which means there is nothing half-saved to clean up. See [Teach from a demonstration](/bot/teach). -| Code | Meaning | -| --- | --- | -| [`no_capacity`](/problems/no_capacity) | No guest could be started right now; try again shortly | -| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Too many bots or turns active at once | -| [`invalid_state`](/problems/invalid_state) | The bot or its computer is not in a state that allows the action | +## Not available yet, so there is nothing to fix + + +Some surfaces are built but not wired up on this deployment, and no setting will turn them on. Bot rooms and room sharing: `This deployment does not host bot rooms yet. Nothing was started.` Bot packs and duplicating a bot. Browsing or downloading a bot's workspace files. Editing the egress allow list. Minting a public share link: `Cortex cannot mint a link yet, so nothing here writes.` Inbound mail: `Inbound mail is not configured on this deployment.` Live voice: `Live voice is not available on this deployment.` The companion roster: `The companion roster is not served here yet.` + + +There is also no per-turn cost line to look up for a bot: `The cost ledger is not configured on this deployment.` If a bot action failed, the reason is the message it gave you, so work from that rather than looking for a billing explanation. Channels, routines, tasks, secrets, memory, skills, tool policy and teaching are all live, and [Channels](/bot/rooms) and [Share a bot](/bot/sharing) say which half of each pair works today. + +## Error codes you may see + +| Code | On a bot this means | What to do | +| --- | --- | --- | +| [`no_capacity`](/problems/no_capacity) | no computer could be started right now | try again shortly | +| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | too much at once, such as a second desktop task | let the first one finish | +| [`invalid_state`](/problems/invalid_state) | the action does not apply in the computer's current state | check the rail, then wake or start the computer | -Full list: [Problem catalog](/problems). +Every code has its own page in the [Problem catalog](/problems), and [Errors](/reference/errors) explains how to read one. If several things fail at once across products, check [System status](/reference/status) before debugging your own bot. ## Related -- [Computer](/bot/computer) — the guest states behind Connecting and Stream Unavailable. -- [Approvals](/bot/approvals) — why a parked step waits. -- [Routines](/bot/routines) — local weekday timing. -- [Troubleshooting](/getting-started/troubleshooting) — the same guidance across all products. +- [Computer](/bot/computer) - the desktop rail, the stream, control handover, and recreating a computer. +- [Approvals and tool policy](/bot/approvals) - which tools ask, what **Always** writes, and where parked steps collect. +- [How Bot works](/bot/how-it-works) - what a turn is, what ends one, and what the bot can say. +- [Routines](/bot/routines) - schedules, weekday hours, and paused copies. +- [Troubleshooting](/getting-started/troubleshooting) - sign-in, updates and the rest of the app. diff --git a/bounty/index.mdx b/bounty/index.mdx new file mode 100644 index 0000000..5cd8ea7 --- /dev/null +++ b/bounty/index.mdx @@ -0,0 +1,97 @@ +--- +title: "Cortex Bounty" +description: "The Cortex Bounty Challenge: pair a mining hotkey, file a report from Chat, and read every verdict on a public log" +icon: "coins" +--- + +Cortex Bounty is the **Cortex Bounty Challenge**, a bug bounty for miners on the Cortex subnet. You pair a mining hotkey to a Cortex account, look for a real defect in Cortex inside a marked conversation, file a report, and wait for a verdict. Every verdict that is reached is published on a log that anyone can read without signing in and without a credential. + +Cortex plays three parts in the programme: it records your pairing and the session context, it adjudicates the reports that are filed, and it publishes the public transparency log. It does not set weights and it does not compute a score. The subnet reads the public endpoints and sets weights from the valid rows it finds there. + +## The four pages of this section + + + + Accept the terms, sign the payload the CLI prints, and link an SS58 hotkey to your mining account. + + + Mark a conversation as a miner session, file from Chat, and see what the report carries. + + + The four statuses, the gates a row has to clear, and what can never become a valid row. + + + The unauthenticated public endpoints, windows and paging, and how to read a zero. + + + +## Before you start + +Use a **dedicated mining** Cortex account, not your private personal account. The programme terms are explicit about why: "Conversations, logs, and the account may be read for research, to fix bugs, and to remunerate you." + + +Accepting the terms is blocking. Until the terms are accepted, pairing is refused and so is marking a conversation as a miner session. The version in force is `bounty-research-v1`, and what is stored with your acceptance is your account id, that version, and a timestamp. + + +## How it flows end to end + + + + Sign in to Cortex with an account you keep for mining. See [Accounts and sign-in](/getting-started/accounts). + + + Install the Cortex CLI and run the pairing command. The CLI prints an exact string, you sign it with your own wallet tool, and the hotkey is linked. Full procedure on [Pair a hotkey](/bounty/pair-a-hotkey). + + + Pairing prints a command to send in Chat, plus a one-time session code. Sending that command marks the conversation as a bounty-miner session and injects miner context. + + + Describe what you found in the marked conversation, then file it with the Chat report tool. See [File a report](/bounty/report). + + + A filed report is pending and private. It is not on the public endpoints, and fetching it by id answers as though it did not exist, until a verdict exists. + + + Once a verdict is recorded, the row becomes public. Anyone can read it, count it and verify it with the [Transparency API](/bounty/public-api). + + + +## What a machine decides and what a person decides + +Two different kinds of decision sit in this programme, and it is worth knowing which is which before you file. + +| Decided mechanically | Decided by judgement | +| --- | --- | +| Whether the terms are accepted, and therefore whether you may pair or mark a session at all | Whether what you found is a real, unique defect | +| Whether a hotkey is already held by another account | Which of the four statuses your report receives | +| Whether a report has enough substance to be published at all | The wording of the finding and the reasoning recorded with the verdict | +| Whether a row appears on the public endpoints, and in which window | Whether a report duplicates an earlier one, and which one it names | + +The mechanical gates are described in full on [Verdicts and scoring](/bounty/scoring). They are the usual reason a report you consider valid has not appeared on the public log. + +## What this section does not tell you + +This documentation covers the mechanics: pairing, filing, verdicts, and the public log. It does not state what a reward is worth, when a verdict will arrive, or who is eligible to take part. Those belong to the programme's own terms, the ones you accept at pairing, and they can depend on the case. Do not read an amount or a schedule into the three outcomes described on the scoring page. + +## How it fits with the other Cortex products + +Cortex Bounty is a programme rather than an application you open, so it borrows the surfaces of two products you already have. + +- The [Cortex CLI](/cli/index) does the pairing. It is the only place the pairing command runs, and the only place the string you have to sign is printed. +- [Cortex Chat](/chat/index) is where a report is filed, from a conversation that has been marked as a miner session. The report tool is not offered in an ordinary conversation. +- The Transparency API stands on its own. It needs no account, so a third party can check a payout claim without your help. + +If you have found a defect but are not a miner on the subnet, this is not your intake. Use [Report a bug](/getting-started/report-a-bug) instead. + + +Not part of this programme, and not a Cortex feature: `/miner` is not a command and never will be, there is no attestation surface here, and there is no teacher host. The subnet runs its own pipeline beyond the public log, and nothing in it is documented on this site. + + +## Related + +- [Pair a hotkey](/bounty/pair-a-hotkey) +- [File a report](/bounty/report) +- [Verdicts and scoring](/bounty/scoring) +- [Transparency API](/bounty/public-api) +- [Install the CLI](/cli/install) +- [Report a bug](/getting-started/report-a-bug) diff --git a/bounty/pair-a-hotkey.mdx b/bounty/pair-a-hotkey.mdx new file mode 100644 index 0000000..15af4ce --- /dev/null +++ b/bounty/pair-a-hotkey.mdx @@ -0,0 +1,100 @@ +--- +title: "Pair a hotkey" +description: "Accept the Cortex Bounty terms and link an SS58 mining hotkey to your Cortex account by signing the payload the CLI prints" +icon: "key" +--- + +Pairing is the first thing you do in [Cortex Bounty](/bounty/index). It links a mining hotkey to a Cortex account, so that a report filed from that account can be credited to that hotkey on the public log. Nothing else in the programme works until a hotkey is paired: the Chat report tool is not offered, and a conversation cannot be marked as a miner session. + +Pairing happens entirely in the terminal, with the Cortex CLI. It proves two things at once, that you control the Cortex account and that you control the hotkey, by having you sign a string the CLI prints with your own wallet tool. This page covers what you need, the exact command, what you sign, and how many hotkeys one account may hold. + +## What you need + +- A **dedicated mining** Cortex account. Reports, conversations and logs on it may be read for research, to fix bugs, and to remunerate you, so do not use a private personal account. See [Accounts and sign-in](/getting-started/accounts). +- The Cortex CLI installed. The binary is `cortex`. See [Install the CLI](/cli/install). +- Your hotkey's SS58 address, and a wallet tool that can sign an arbitrary string with it. **btcli** and **polkadot-js** both do this. + + +Cortex never asks for a mnemonic. The CLI prints a string and asks for a signature over it. Nothing in this flow needs your seed phrase, your private key or a wallet file, and no Cortex surface will ever ask for one. + + +## Accept the terms + +The terms version in force is `bounty-research-v1`. It is shown to you at pairing, and your acceptance is stored as three things: your account id, that version, and a timestamp. + +Acceptance is blocking rather than advisory. Until the terms are accepted, pairing is refused and so is marking a conversation as a miner session. You accept them as part of the pairing command, with `--accept-terms`. + +## Pair the hotkey + + + + Pass the SS58 address of the hotkey you want to link. + + ```bash + cortex bounty pair --hotkey --accept-terms + ``` + + + The CLI signs you in. If you already have an access token you can supply it to the CLI with `--token` instead of signing in. See [Sign in to the CLI](/cli/sign-in). + + + The CLI asks the challenge backend for a nonce, then prints the exact string to sign. It has four parts separated by a vertical bar: a fixed prefix, your account id, the nonce, and an expiry. + + ```text + cortex-bounty-v1|{account_id}|{nonce}|{exp} + ``` + + Sign that string exactly as printed, byte for byte. Do not reformat it, do not trim it, and do not sign the address or a hash of your own making. + + + Use **btcli** or **polkadot-js** to sign the string with the hotkey named in the command. The signature is produced entirely on your side. + + + Hand the signature back to the CLI. When it is accepted, the hotkey is linked to the account and pairing is done. + + + Pairing prints two things you need in Chat: the command that marks a conversation as a miner session, and a one-time session code. Keep both. The command is a secret and must not be shared or posted anywhere. + + + +## What pairing gives you + +| What you get | What it is for | +| --- | --- | +| A linked hotkey | Reports filed from this account can be credited to this hotkey | +| An accepted terms record | Unblocks pairing and the miner session marking | +| The Chat command | Marks a conversation as a bounty-miner session. See [File a report](/bounty/report) | +| A one-time session code | An optional argument, sent in Chat straight after that command | + +The Chat command is configured by an operator, which is why the CLI prints it for you rather than this page naming it. Treat it as a credential: anyone holding it can mark a conversation. `/miner` is not that command, is not a command at all, and never will be. + +## Many hotkeys per account, one account per hotkey + +One Cortex account can hold as many hotkeys as you pair to it. Run the command again with another SS58 for each one. + +The reverse does not hold. A hotkey belongs to exactly one account, and a second account cannot claim a hotkey that is already paired. The practical consequence is worth stating plainly: **you cannot move a hotkey between accounts by pairing it again elsewhere.** Decide which account is your mining account before you pair, because pairing is not a way to migrate one later. + +## If pairing does not go through + + + + The usual cause is the terms. Pairing is refused until `bounty-research-v1` is accepted, which is what `--accept-terms` does. Run the command with that flag. + + + That hotkey is paired to another Cortex account. Nothing you can do from this account changes that, and a second claim is refused by design. Use a hotkey that is not yet paired, or sign in to the account that holds it. + + + The string has to be signed exactly as printed, and the payload carries an expiry as its last part. If that expiry has passed, run the pairing command again and sign the new payload without editing it. Check also that you signed with the hotkey named in the command rather than another key in your wallet. + + + Every Cortex failure has one shape and a stable code, and it carries a reference id that is safe to quote. See [Errors](/reference/errors). + + + +## Related + +- [Cortex Bounty](/bounty/index) +- [File a report](/bounty/report) +- [Verdicts and scoring](/bounty/scoring) +- [Install the CLI](/cli/install) +- [Sign in to the CLI](/cli/sign-in) diff --git a/bounty/public-api.mdx b/bounty/public-api.mdx new file mode 100644 index 0000000..f5900ad --- /dev/null +++ b/bounty/public-api.mdx @@ -0,0 +1,114 @@ +--- +title: "Transparency API" +description: "Four unauthenticated endpoints that publish every adjudicated Cortex Bounty report, with windows, paging, and how to read a zero" +icon: "globe" +--- + +The transparency API is how a Cortex Bounty verdict becomes checkable by anyone. It is four read-only endpoints that need no account, no credential and no cookie, and none is minted for the caller. A participant can verify their own row with it, and a third party can verify somebody else's claim without asking either side for access. + +The endpoints publish adjudicated reports only. Nothing pending appears, no conversation appears, and no account is identified. This page lists the four paths, then covers the three things that trip people up: time windows, paging, and what a zero actually means. Each path below is given relative, so prefix it with the Cortex API host for the deployment you are checking. + +## The four endpoints + +All four are `GET`, and all four are unauthenticated. + +| Path | Query parameters | What it answers | +| --- | --- | --- | +| `/v1/bounty/public/status` | none | Is this backend adjudicating at all? Counts, backlog, and whether an operator exists | +| `/v1/bounty/public/leaderboard` | `since`, `until` | Hotkeys ranked by valid-report count, plus counts by status. No account ids | +| `/v1/bounty/public/reports` | `hotkey`, `status`, `since`, `until`, `limit`, `cursor` | Adjudicated reports, completely enumerable | +| `/v1/bounty/public/reports/{id}` | none | One adjudicated report, or 404 if it is pending or unknown | + +Every response from all four carries `api_version`, which is `1` today, and `generated_at`, the moment the response was built. Every response is sent with `cache-control: no-store`, so what you read is what the log says now rather than something a cache kept. + +## What a public row contains + +| Field | Meaning | +| --- | --- | +| `id` | The report id. A time-ordered id assigned when the report was filed | +| `hotkey` | The SS58 address the report was credited to. Never an account id | +| `status` | One of the four verdicts. See [Verdicts and scoring](/bounty/scoring) | +| `problem_found` | What the defect was, as recorded by the adjudicator | +| `justification` | The reasoning behind the status | +| `adjudicator` | An agent or service identifier. Never a person, never an email address | +| `adjudicated_at` | When the verdict was recorded | +| `created_at` | When the report was filed | +| `related_report_id` | Present on duplicates only, and the report it names is already public | + +Chat transcripts stay private. They are never on the public routes, and neither is the report body, your email address, your display name, a conversation id, a pairing code or a token of any kind. The full list is on [File a report](/bounty/report). + +## Windows + +`since` and `until` are RFC 3339 timestamps, and they behave the same way on the leaderboard and on the reports listing. + +- `since` is **inclusive**. `until` is **exclusive**. So consecutive windows can share a bound without double-counting a row. +- Both filter on `adjudicated_at`, the moment the verdict was recorded. Neither filters on filing time. A report filed in one window and judged in the next belongs to the second. +- `until <= since` is **refused**. It is not answered with an empty page, and the reason is worth understanding: an empty page reads exactly like "this hotkey earned nothing". +- An `adjudicated_at` value taken from a response is reusable as a bound byte for byte. It is truncated to microseconds. A `+00:00` offset needs percent-encoding in a query string, though the un-encoded form is accepted too. + +## Paging the reports listing + +The reports endpoint is the one that enumerates completely, and it is cursor-paged. + +```text +/v1/bounty/public/reports?hotkey=HOTKEY&since=FROM&until=TO&limit=100 +``` + +- `limit` is clamped to **100**. Asking for more gets you 100. +- The response reports `has_more`. While it is true, send `next_cursor` back verbatim as `cursor` and read the next page. +- The cursor is opaque, and it is keyed on `adjudicated_at` and then `id`. Do not build one yourself and do not try to decode it. +- `id` is assigned at filing time, not at verdict time, so ids are not in verdict order. That is exactly why the cursor exists: you cannot page this log by sorting ids. + +The leaderboard is **not** paged. It aggregates up to **1000** hotkeys and sets `has_more` when there are more than that. If you need a complete enumeration, walk the reports endpoint instead. The leaderboard is a summary, and the reports listing is the record. + +## Reading zero correctly + +This is the part to get right before you conclude anything from an empty result. A zero on the leaderboard has three different meanings, and the status endpoint is what tells them apart. + +| What the status endpoint says | What it means | Is it a real zero? | +| --- | --- | --- | +| `adjudication_available` is false | No operator is adjudicating | No. Nothing is being judged at all | +| `awaiting_adjudication` above zero, nothing published | A queue exists but has not been worked | No. The verdicts have not happened yet | +| `adjudication_available` true and `awaiting_adjudication` zero | Everything filed has been judged | Yes. This is a real zero | + +Two further facts make the reading safe. A backend that cannot answer at all fails the request; it never answers an empty list, so an empty list is always a real answer from a working backend. And `last_adjudicated_at` on the status response tells you how stale the log is, which is the difference between "nothing has happened" and "nothing has happened lately". + +| Status field | Meaning | +| --- | --- | +| `adjudication_available` | Whether an operator is adjudicating at all | +| `awaiting_adjudication` | How large the backlog is | +| `last_adjudicated_at` | How stale the log is | +| `api_version` | The response contract version, `1` today | +| `generated_at` | When this response was built | + +## Verify one bounty end to end + + + + Read `/v1/bounty/public/status`. Confirm that an operator exists and that the backlog is zero. If it is not, stop here: anything you count next is incomplete by definition. + + + Call `/v1/bounty/public/leaderboard` with the `since` and `until` bounds of the window you care about. Note the valid-report count for the hotkey you are checking. + + + Call `/v1/bounty/public/reports` with the same `hotkey`, `since` and `until`, and follow `next_cursor` until `has_more` is false. Count the valid rows as you go. + + + Take an id from the walk and read `/v1/bounty/public/reports/{id}`. You get the same row, which is the one you can quote to somebody else. + + + The count from the leaderboard and the rows you walked must agree. A disagreement means the walk was truncated, so check `has_more` and page again. It does not mean the log is wrong. + + + + +There is no public API for anything else in Cortex. These four endpoints exist because the bounty log has to be verifiable by outsiders; they are not a general platform API, and there is no inference endpoint, no API key and no client library. See [Platform API](/reference/platform-api). + + +## Related + +- [Cortex Bounty](/bounty/index) +- [Verdicts and scoring](/bounty/scoring) +- [File a report](/bounty/report) +- [Platform API](/reference/platform-api) +- [Errors](/reference/errors) diff --git a/bounty/report.mdx b/bounty/report.mdx new file mode 100644 index 0000000..26d64c3 --- /dev/null +++ b/bounty/report.mdx @@ -0,0 +1,94 @@ +--- +title: "File a report" +description: "Mark a Chat conversation as a bounty-miner session, file a report with the Chat report tool, and see what the report carries" +icon: "flag" +--- + +A Cortex Bounty report is filed from [Cortex Chat](/chat/index), out of the conversation in which you found the problem. The conversation itself is the evidence: you describe the defect in it, then file the report from inside it, and the report is tied to that conversation, to the hotkey you are mining with, and to the account that filed it. + +Two things have to be true before the report tool appears. A hotkey must be paired to the account, which is covered on [Pair a hotkey](/bounty/pair-a-hotkey), and the conversation must be marked as a bounty-miner session. This page covers the marking, the filing, what the report carries, and what stays private while a verdict is pending. + +## Mark a conversation as a miner session + +Marking is what turns an ordinary conversation into a miner session. It also injects miner context, so the assistant knows which hotkey it is working for. + + + + Sign in with the dedicated mining account and start a fresh conversation in Chat. + + + Pairing printed a command to send in Chat. Send it in the composer as an ordinary message. You can send it on its own, or follow it with the one-time session code, or with the SS58 address of any hotkey already linked to the account. + + + The conversation is now a bounty-miner session and miner context has been injected. The report tool is available in it. + + + If the account holds several hotkeys, send the command again with the SS58 address of the one you want. The conversation follows the hotkey you name last. + + + + +The command is a secret. It is set by an operator, the CLI prints it only to you, and anyone holding it can mark a conversation. Do not paste it into an issue, a screenshot, a support thread or a public repository. `/miner` is not that command and is not a command at all. + + +## File the report + +Work the problem in the conversation first. Reproduce it, narrow it down, and write out what you found in plain language, because that text is what an adjudicator will read and what the publication gates are measured against. + +When the finding is written up, file it with the `bounty_report` tool. It is a Chat tool and it is only offered in a conversation that has been marked as a miner session, so it will not show up in a normal thread. You can add hints alongside the body when there is something an adjudicator should know to reproduce it. + + +Write the finding out properly rather than filing a one-line note. A report whose body carries less than 24 characters of plaintext finding can never be published as a valid row, whatever an adjudicator thinks of it. See [Verdicts and scoring](/bounty/scoring). + + +## What a report carries + +| In the report | Where it comes from | +| --- | --- | +| The hotkey | The linked SS58 the session is mining for | +| The account id | The Cortex account that filed it | +| The session id | The conversation the report was filed from | +| A creation timestamp | Set when you file | +| The body | What you wrote up in the conversation | +| Optional hints | Anything you added for the adjudicator | + +Reports are delivered to the challenge backend, which is what adjudicates them and what publishes the verdicts. Nothing you file goes to the subnet directly. + +## While it is pending, it is private + +A filed report has no status yet. Until a verdict exists: + +- It does not appear on any of the public endpoints. It is not counted on the leaderboard, and it is not in the reports listing. +- Fetching it by its id answers 404, exactly as an id that never existed would. That is deliberate. The public log holds adjudicated rows and nothing else. +- You can still see it yourself. A signed-in participant can list their own reports, pending ones included, and that is the only way to see a pending report. + +So an empty public log is not evidence that your report was lost. It is the expected state of a report that has not been judged yet. The [Transparency API](/bounty/public-api) explains how to tell a backlog apart from a real zero. + +## What is never published + +The conversation is the one thing that never becomes public. **Chat transcripts stay private. They are never on the public routes.** The report body is sealed too: its length is checked as a publication gate, but the text itself is never published. + +| A public row carries | A public row never carries | +| --- | --- | +| The report id | Your Cortex account id | +| The hotkey, as an SS58 address | Your email address | +| The status | Your display name | +| The finding recorded by the adjudicator | Chat transcripts | +| The justification for the verdict | Conversation or session ids | +| An adjudicator identifier | Pairing codes, or the Chat command | +| The verdict timestamp and the filing timestamp | IP addresses | +| A related report id, on duplicates only | Tokens of any kind, and the raw report body | + +What an adjudicator writes about your report does become public, in two fields: a statement of the problem found, and the justification for the verdict. Nothing you wrote is republished verbatim. + +## What this page cannot tell you + +There is no published turnaround time for a verdict, and no queue position you can read for your own report. The status endpoint tells you whether anyone is adjudicating at all and how large the backlog is, which is the closest thing to a progress signal that exists. Rewards, eligibility and timing are set by the programme terms you accepted at pairing rather than by this documentation, and they can depend on the case. + +## Related + +- [Cortex Bounty](/bounty/index) +- [Pair a hotkey](/bounty/pair-a-hotkey) +- [Verdicts and scoring](/bounty/scoring) +- [Transparency API](/bounty/public-api) +- [Built-in tools](/chat/tools) diff --git a/bounty/scoring.mdx b/bounty/scoring.mdx new file mode 100644 index 0000000..7a69e2f --- /dev/null +++ b/bounty/scoring.mdx @@ -0,0 +1,88 @@ +--- +title: "Verdicts and scoring" +description: "The four Cortex Bounty statuses, the gates a verdict has to clear before it is published, and what can never become a valid row" +icon: "scale-balanced" +--- + +Every Cortex Bounty report ends in one of four verdicts, and only one of them is a reward. This page explains what the four statuses mean, what a verdict has to carry before it can be published at all, and the list of reasons a report you consider valid never turns into a valid row on the public log. + +It is worth being precise about who decides what. The gates below are mechanical: a verdict that does not satisfy them is refused, and no adjudicator can wave it through. The verdict itself is a judgement about your finding, made by an adjudicator working for the programme. Cortex does not compute a score here, and the reward is not decided on this site. + +## The four statuses + +| Status | Public? | Effect | +| --- | --- | --- | +| pending, no status yet | No. Its id answers 404 | None. The report has not been judged | +| `valid` | Yes | Reward | +| `duplicate` | Yes | Not a valid row. May name a related report | +| `already_fixed_not_prod` | Yes | No penalty | +| `invalid_malicious` | Yes | Penalty | + +Read in outcome terms, that is three possibilities and nothing in between. + +| What you filed | What happens | +| --- | --- | +| A valid, unique bug | Reward | +| Something already fixed and not in production | No penalty | +| Something malicious, or a problem that does not exist | Penalty | + + +This documentation does not state what a reward is worth or when it arrives, because no amount and no schedule is published here. Those come from the programme terms you accepted at pairing, and they can depend on the case. Treat "reward", "no penalty" and "penalty" as the direction of the outcome, not as a figure. + + +## What a verdict has to carry + +A verdict is refused unless it carries both of these, and each has to be at least 16 characters long: + +- **problem found**, a statement of what the defect actually was. +- **justification**, the reasoning behind the status that was chosen. + +The adjudicator recorded on the row is an agent or service identifier. It is never an email address, so a public row never names a person. Once a verdict satisfies these conditions the row becomes public, and the verdict is written to the audit chain as well. + +Both of those fields are published. They are the only description of your report that anyone else can read, since the report body itself stays sealed. + +## What can never become a valid row + +Use this as a checklist when a report has not appeared where you expected it. + + + + A pending report is not public at all. Its id answers 404 until a verdict exists, and it is counted nowhere. Check the status endpoint before concluding anything: a backlog is not a verdict. See [Transparency API](/bounty/public-api). + + + A `valid` row cannot be published unless the report body holds at least **24 characters** of plaintext finding. The body stays sealed and is never published; the length is only a publication gate. A one-line note fails it. + + + The problem found and the justification each need at least **16 characters**. A verdict that does not meet that is refused rather than published, so the row stays pending. + + + The oldest reports, filed before the sealed field that gate reads existed, cannot be credited. + + + A `duplicate` never counts as `valid`, however good the finding is. When a duplicate names a related report, that related report must already be public, so you can go and read the one that got there first. + + + One hotkey belongs to one account. A second account cannot claim a hotkey that is already paired, so a report filed from the wrong account is not credited to that hotkey. See [Pair a hotkey](/bounty/pair-a-hotkey). + + + +## An unrecognised verdict is withheld + +If a row carries a status this version of the public log does not recognise, the row is withheld rather than shown. It is specifically **not** rendered as `invalid_malicious`. + +That matters for anyone reading the log with a script. A future status will simply not appear, rather than turning up mislabelled as a penalty. A row you cannot see is never proof of a penalty, and a count that comes up short is a reason to check `has_more` on your walk, not evidence of a lost report. + +## How weights follow valid rows + +Cortex adjudicates and publishes. It does not set weights. + +The subnet reads the public endpoints and sets weights from the valid rows it finds there. There is no separate score inside Cortex, no ranking that is not derived from the public log, and nothing hidden behind sign-in that changes the outcome. That is the whole point of publishing the log: the input to the weighting is the same document you can read. + +For the same reason, the subnet's own pipeline is outside this documentation. What happens to a valid row after the subnet reads it, including anything about epochs, is not a Cortex feature and is not described on this site. There is no attestation surface here and there is no teacher host. + +## Related + +- [Cortex Bounty](/bounty/index) +- [File a report](/bounty/report) +- [Transparency API](/bounty/public-api) +- [Pair a hotkey](/bounty/pair-a-hotkey) diff --git a/changelog.mdx b/changelog.mdx index a47438a..536c424 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -1,16 +1,12 @@ --- title: "Changelog" -description: "What shipped in Cortex Chat, Code, Bot, Design, and the CLI — dated, with a link to the surface it changed." -image: "/images/banners/changelog.png" +description: "What shipped in Cortex Chat, Code, Bot, Design, Security, and the CLI, dated, with a link to the surface it changed." +icon: "clock-rotate-left" keywords: ["release notes", "updates", "what is new"] --- Dated notes on what the products ship. Each entry names a change the app or the CLI already carries and links the surface it touched. Announcements from the Foundation are on [cortex.foundation/news](https://cortex.foundation/news). - - Cortex Chat, Cortex Code, and Cortex Bot are live — Cortex Foundation announcement - - - **`/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). @@ -47,10 +43,10 @@ Dated notes on what the products ship. Each entry names a change the app or the ## How this page is kept -An entry names a change the product already ships, with a date, and links the surface. Product previews stay labelled as previews. The inference Platform API is not announced here until that product exists — see [Coming soon](/platform). +An entry names a change the product already ships, with a date, and links the surface. Product previews stay labelled as previews. The inference Platform API is not announced here until that product exists — see [Coming soon](/reference/platform-api). ## Related -- [System status](/status) — outages and maintenance, which are not changelog entries. -- [CLI](/cli) — install and update, including `cortex upgrade`. -- [Platform API](/platform) — why no inference API is announced here yet. +- [System status](/reference/status) - outages and maintenance, which are not changelog entries. +- [CLI](/cli) - install and update, including `cortex upgrade`. +- [Platform API](/reference/platform-api) - why no inference API is announced here yet. diff --git a/chat/attachments.mdx b/chat/attachments.mdx new file mode 100644 index 0000000..5899ce7 --- /dev/null +++ b/chat/attachments.mdx @@ -0,0 +1,109 @@ +--- +title: "Attachments and files" +description: "Send a file with a message: what Cortex Chat accepts, the 10 MB ceiling, what text is read out of a document, and where uploads land" +icon: "paperclip" +--- + +You can send a file along with a message in Cortex Chat. Pick it from your computer, drag it onto the composer, or choose one you already have in Library or on a connected cloud drive. The file is uploaded, kept in [Library](/chat/library), and referenced by the turn you attached it to. + +This page covers how to attach a file, what Chat accepts, the size ceiling and where it is enforced, what Cortex can read out of a document, and the messages you see when an upload or an extraction does not work. + +## Attach a file + + + + Click **Attach a file** in the composer. The menu offers a local file, **From your Library**, and **Cloud drives**. A drive you have not connected shows **Connect** instead of a file list. + + + The file appears as a chip above the composer. It reads **Uploading…** with a percentage while the transfer runs, then settles to the file name. The chip states the ceiling: **10 MB max**. + + + **Remove** with the file name drops the attachment. The same button cancels an upload that is still running. + + + Write your question and send. The file is in Library afterwards, so you can attach it again later without uploading it a second time. + + + +Images and video have their own control, **Add image or video**, which builds a small rail of media instead of document chips. It refuses anything that is not one of those with **That file is not an image or video the composer can attach.** + +## What Chat accepts + +| Kind | Extensions | +| --- | --- | +| Images | `.png`, `.jpg`, `.jpeg`, `.webp`, `.gif` | +| Video | `.mp4`, `.webm`, `.mov` | +| Documents | `.pdf`, `.docx`, `.xlsx` | +| Text and data | `.json`, `.txt`, `.md`, `.csv` | +| Origin check only | `.heic`, `.heif` | + +A file type outside this list is refused as an unsupported media type. See [Unsupported media type](/problems/unsupported_media_type). + +Photos in the `.heic` and `.heif` formats are accepted for a provenance check but not as chat images. The message says so: **HEIC photos can be checked for origin. Use Check origin, or convert to JPEG or PNG.** See [Check origin](/chat/origin-check). + +## The size ceiling is 10 MB + +The composer applies a single limit of **10 MB per file**, and it applies to everyone. The check happens in your browser before the upload starts, so an oversized file is refused straight away instead of wasting a long transfer. The media rail refuses the same way, with **That file is larger than the attach limit.** + +If a file is too large, the fix is to split it, export a smaller range, or attach the relevant part as text. + + +Uploading requires an account. Signed out, you get a working conversation but no uploads. If an upload is refused on your plan before the size check even runs, that is an entitlement refusal rather than a size problem, and [Entitlement required](/problems/entitlement_required) explains what to do. + + +A message that is rejected for size, whether it is the file or the text of the message itself, shows up as [Payload too large](/problems/payload_too_large). + +## What Cortex reads out of a file + +Uploading is only half the job. Cortex then tries to read text out of what you sent, and the chip says **Reading** with the file name while that happens. + +| File | What happens | +| --- | --- | +| `.docx` and `.xlsx` | The text is pulled out and included with your message | +| `.pdf` | Attached and referred to by name, rather than having its text pulled into the message | +| `.txt`, `.md`, `.csv`, `.json` | Read as the text they already are | +| Encrypted or damaged files | Nothing is read, and you are told rather than left guessing | + +An unreadable file fails plainly: **That file is encrypted or unreadable. Cortex did not extract it.** If that happens on a document you know is fine, an export to plain text or a re-save from the original application usually fixes it. + +When an answer quotes something from a file, the citation names the file and the place inside it, so a claim can be checked against the source. The shape is the file name followed by a locator, for example `report.pdf · p.12` or `forecast.xlsx · Sheet 1`. + +## Images + +You can attach an image, and the composer will upload it like anything else. What a model does with it is another matter: neither model published in Chat today advertises image understanding, so do not build a question around Cortex reading what is inside a picture. See [Models and thinking](/chat/models). + +There is one thing a picture is definitely good for. If your question is whether an image was generated or edited rather than what it shows, run it through [Check origin](/chat/origin-check), which is built for exactly that and accepts the widest set of photo formats. + +## Where uploads land + +Every file you attach is stored in [Library](/chat/library), not only inside the conversation. Two consequences are worth knowing: + +- Deleting a chat does not delete the files you attached to it. They stay in Library until you remove them there. +- A file already in Library can be attached to any later chat through **From your Library**, with no second upload. + +Files are yours alone. Chat is per account, so an attachment is visible only to the account that uploaded it. Sharing a result means exporting or copying it, as described in [Sharing and teams](/chat/sharing). + +## When an upload will not work + + + + The transfer did not complete. The chip turns to an error state and keeps the file name. Remove the chip and attach the file again; if it fails repeatedly on a large file, check your connection before blaming the file. + + + It is refused before the upload starts, so nothing was transferred. Reduce or split the file. + + + The file uploaded but could not be read, which is usually password protection or corruption. The file is still in Library; the text simply did not reach the model. + + + Attaching needs an account. Sign in with your Cortex account and the control appears. + + + +## Related + +- [Library](/chat/library) - where every upload and generated file is kept. +- [Check origin](/chat/origin-check) - test whether a photo was generated or edited. +- [Models and thinking](/chat/models) - what the current models do and do not handle. +- [How Chat works](/chat/how-it-works) - how an attachment becomes part of a turn. +- [Chat troubleshooting](/chat/troubleshooting) - upload and extraction messages in context. diff --git a/chat/canvases.mdx b/chat/canvases.mdx index aa19e75..8622d18 100644 --- a/chat/canvases.mdx +++ b/chat/canvases.mdx @@ -1,55 +1,85 @@ --- title: "Chat canvases" -sidebarTitle: "Canvases" -description: "A document that sits beside the conversation. Draft it yourself or ask Cortex to — and keep editing after the chat moves on." -keywords: ["document", "sidecar", "editor", "draft"] +description: "A document that sits beside a conversation. Cortex drafts into it, you edit it, and it saves itself while you type." +icon: "file-pen" --- -A Chat canvas is a document panel beside a conversation. Cortex can draft it, you can edit it, and it keeps your edits when you close it. It is the right place for a launch announcement, a spec, or anything you want to shape over several turns instead of scrolling back through replies. +A Chat canvas is a plain document that opens in a rail beside a conversation. Cortex can draft into it while you watch, and you can type in the same document at the same time. It is the right place for anything you want to shape over several turns, such as an announcement or a short spec, instead of scrolling back through the transcript to find the good paragraph. - - Chat with an Untitled document canvas open beside the conversation - +This page covers how to open a canvas, how it saves itself, how to ask Cortex to rewrite part of it, how a canvas differs from a plan, a Library note, a Code file and a Design canvas, and what to do when the rail will not open or save. ## Open a canvas -- Choose the **Docs** card on Chat home — *Drafts that structure themselves*. It opens a new chat with an **Untitled document** beside it. -- Or ask in any thread: *Draft this as a document I can edit.* + + + Type `/` in the composer to open the slash palette, then choose **Canvas**. Its hint reads `Open a document`. The rail opens on an empty document. + + + Select text inside an answer. The selection menu, **Selected answer actions**, offers **Start writing**, which starts a canvas from that selection. + + + A canvas belongs to the conversation it was created in, so reopening that conversation is how you get back to the document. A conversation link can also carry a document reference, in which case the rail opens on that document straight away. + + -## Work in a canvas +## Work in the document -1. Ask Cortex to draft or revise — *tighten the intro*, *add a section on pricing*. -2. Edit directly in the panel. The conversation and the document stay in step. -3. **Close** the panel when you are done; your edits are kept with the conversation. +The rail has two fields. The title field is **Document title**, with the placeholder `Untitled document`. The body field is **Document body**, with the placeholder `Start writing, or ask Cortex to draft this document.` -## What writes to it +You do not save the document yourself. About half a second after you stop typing, the rail saves what you have written: the status reads `Saving…` while the save is in flight and `Saved` when it lands. **Close** puts the rail away and flushes any pending save before it closes, so closing the rail immediately after a sentence does not lose the sentence. -Canvas tools are part of the tool set a Chat turn can receive, alongside the document readers. A turn reaches them the same way it reaches any other tool — the model asks, Chat runs it. See [How Chat works](/chat/how-it-works). +| What the rail shows | What it means | +| --- | --- | +| `Loading` | the document is being fetched | +| `Saving…` | your last edits are being written | +| `Saved` | everything you have typed is stored | +| `The document could not be opened.` | the document did not load; the rail says so rather than showing an empty one | +| `The document could not be saved.` | the last save failed; copy anything you cannot afford to lose before retrying | -Two of those tools are for Design boards rather than documents: `design_write` and `design_read`. Chat can host a **Design** canvas through them, and that object opens in the Design desktop app. See [Design](/design). +## Ask Cortex to write into it -## Canvas, plan, or Library? +Once the rail is open, the conversation is your editor of last resort: ask in the composer for the change you want, in the same words you would use with a person. "Tighten the intro." "Add a section on pricing." The rail refreshes as Cortex writes, and you can keep typing in it meanwhile. A canvas is a document Cortex writes into, not a draft message waiting in the composer, so nothing is pending for you to send. -| You want | Use | -| --- | --- | -| A document you shape over several turns | A **canvas** — this page | -| A task list you tick off | A [plan](/chat/plans) | -| A file you attach or the assistant produced | [Library](/chat/library) | -| A board of frames and notes | A [Design canvas](/design/canvases) | +The model a conversation uses is chosen when the chat starts and does not change for that chat. See [Models and thinking](/chat/models). -## What it is not +## Canvas, plan, note, or file? -| Object | What it is | -| --- | --- | -| **Chat canvas** | A document beside one conversation | -| [Plan](/chat/plans) | A task list linked to a conversation | -| Code file | A file inside a Code session's Cloud guest | -| [Design canvas](/design/canvases) | A board of frames and notes, hosted from Chat or Code, edited in the Design desktop app | +Four different objects can come out of one conversation, and only the first of them is a canvas. -There is no `/design` mode in the web app. Chat can host a **Design** canvas — the object is created from the conversation — but the working UI for it is the Design desktop app. See [Design](/design). +| You want | Use | +| --- | --- | +| A document you shape over several turns, beside one conversation | A canvas, this page | +| A task list that stays linked to the chat and outlives it | [Planning](/chat/plans) | +| One passage of an answer kept as a document | **Save to Library**, below | +| A file you attached, or one Cortex produced | [Library](/chat/library) | +| A board of frames rather than prose | [Design canvases](/design/canvases) | + +A Chat canvas is a text document attached to one conversation and opened from that conversation. It is not a design surface, and it is not a file inside a Code session. + +## Save a selection as a Library note + +When you only want to keep a paragraph, a note is lighter than a canvas. + + + + Choose **Save to Library** from the selection menu. + + + The dialog **Save as Library note** explains: `Edit the title before saving this selection as a Library document.` Edit the **Title** field. + + + Press **Save note**. The confirmation reads `Note saved to Library`, and the dialog states the scope: `Saved in Chat Artifacts. Available from Chat, Code and Bot.` If it fails, the message is `The note could not be saved` with `Please try again.` + + + + +How many canvases one conversation can hold, and how large a single canvas can be, are not published limits. If you are drafting something long, keep a copy outside Cortex as you go. + ## Related -- [Projects](/chat/projects) — keep the chat and its document with the rest of the work. -- [Library](/chat/library) — attachments the draft can draw on. -- [Design canvases](/design/canvases) — the other object called a canvas. +- [Conversations](/chat/conversations) for what else the transcript header can do with a chat. +- [Export documents](/chat/document-export) to turn an answer into a file. +- [Library](/chat/library) for where saved notes and attachments live. +- [Planning](/chat/plans) for the task-list object linked to a chat. +- [Design canvases](/design/canvases) for the other thing called a canvas. diff --git a/chat/conversations.mdx b/chat/conversations.mdx new file mode 100644 index 0000000..c4dba6a --- /dev/null +++ b/chat/conversations.mdx @@ -0,0 +1,147 @@ +--- +title: "Conversations" +description: "Start, name, edit, branch, pin, archive, delete and search your Chat threads, and what a temporary chat does differently" +icon: "message" +--- + +Every exchange in Cortex Chat lives in a conversation, and conversations accumulate. This page covers the whole life of one: starting it, changing a message you already sent, moving between alternative answers, keeping the list in order, finding a thread weeks later, and deleting it when you are done. + +It also covers the things a reader usually goes looking for and does not find: renaming a chat, exporting a whole conversation, sharing one, and a view that lists archived chats. Each of those is called out plainly below rather than left as a hunt. + +## Start a chat + +**New chat** in the sidebar is an action rather than a place. It clears the composer, and the conversation itself is created by your first message: the home page turns into the thread in place, without a reload, and the link in your address bar becomes a stable identifier for it. + +The title arrives on its own. Until it does the row reads **New chat**, then **Naming this chat…** while the title is written, and then the generated title. The title is never put in the link, so a conversation link stays an identifier no matter what the chat ends up being called. If the title cannot be saved you see **The title could not be saved. The thread is unchanged.**, and nothing else about the conversation changes. + + +A chat cannot be renamed. The app refuses with **Chat titles cannot be renamed yet — this app has no route for it.** If a title bothers you, the practical answer is to start a fresh chat with a clearer first message. The **Rename session** control you may have seen belongs to [Cortex Code](/code/sessions) sessions, not to Chat. + + +## The composer, beyond typing + +Typing `/` opens a short palette of things a new message can be: + +| Item | What it does | +| --- | --- | +| **Temporary** | Starts a new chat that is not saved to Recents | +| **Deep Research** | Plans the questions, then writes a cited report | +| **Image** | Prefills a request for a generated picture | +| **Canvas** | Opens a document beside the conversation | + +Three composer behaviours are worth knowing before you meet them. + +- **Offline.** With no network the box reads **You are offline — your message will wait here** and a toast promises **Sending when back online**. Leave the chat before it goes and it is dropped: **A waiting message was discarded because you left this chat.** +- **Steer this reply.** Add a course correction while Cortex is still writing, instead of waiting for it to finish. +- **Queue a follow-up…** holds your next message until the current answer is done, as a **Queued follow-up** chip. **Return queued follow-up to the composer** takes it back. + +When standing instructions are in play, the composer shows **Custom instructions on**. + +## Change your mind about a message + +Nothing in a conversation is destroyed by changing your mind. Messages form a tree, and both controls below add a path rather than overwrite one. + + + + Hover your own message and choose edit. The banner reads **Editing · original kept as Branch 1**. Change the text and press **Send as branch**, or **Cancel**. + + Afterwards the banner counts which branch you are on out of how many exist, with the reassurance **Original kept**, and you move between them from there. + + + Choose **Regenerate** on the answer. The previous answer is kept as a version, and a pager appears showing which version you are reading out of the total, with **Previous version** and **Next version**. It is hidden while there is only one version. + + Switching versions changes which answer is live, and therefore everything that follows from it. + + + **Branch** in the conversation header opens a new chat carrying the pill **Branched from another chat**, so you can take a thread in a second direction without disturbing the first. Where the deployment does not serve it: **Branching from a message is not on this deployment.** + + + +Both editing and regenerating are refused while an answer is being written, with **Wait until the current answer finishes.** Stop the answer first, or wait for it. + +## Pin, archive and delete + +| Task | How | What happens | +| --- | --- | --- | +| **Pin to top** | The chat's actions | It moves to the **PINNED** section | +| **Unpin** | The same menu | It returns to **RECENTS** | +| Archive | The sidebar row action | It leaves Recents immediately. The toast says **Chat archived** and offers **Undo** | +| Restore | **Undo** on that toast | The toast confirms **Chat restored** | +| Delete | The chat's actions, then **Delete chat** in the dialog | Permanent. The toast says **Chat deleted** | + +Pins are capped at 20, shared between chats and projects. Past that, pinning is refused with **You have 20 pinned chats and projects. Unpin one before pinning another.** + +Archiving and deleting are not the same thing, and the difference matters: + +- Archiving only removes a chat from Recents. There is no archived view, filter or page anywhere in the app, so treat archiving as hiding a thread rather than as filing it somewhere you can browse later. An archived chat can still be reached from Chat search. +- Deleting is irreversible. The dialog is explicit about it: **Deleting removes the conversation and its messages. This cannot be undone.** Files you uploaded stay in [Library](/chat/library). + +## How Recents groups your threads + +The sidebar keeps three sections: **WORKSPACE**, **PINNED** (drawn only once you have pinned something) and **RECENTS**. Recents can be grouped three ways. + +| Grouping | Result | +| --- | --- | +| **None** | One flat list, newest first | +| **Day** | Buckets labelled **TODAY**, **YESTERDAY**, **THIS WEEK** and **EARLIER** | +| **Project** | One bucket per project, plus **UNFILED** for everything outside one | + +Threads are also separated into **Chats** and **Research**, so a research run does not bury your ordinary conversations. To move a chat into a project, use **Move to project** under **More chat actions**; see [Projects](/chat/projects). + +## Find a conversation + +Press Cmd or Ctrl with K anywhere in Chat to open Chat search, and type into **Search chats, library, and skills**. Results come back in three groups, **Chats**, **Library** and **Skills**, with up to eight hits each. Arrow keys move, Enter opens, and **Close search** dismisses it. With an empty query the palette lists **Recent chats**, so opening it is useful even before you type. If it cannot run you see **Search could not run.** + +Two things to expect from it: + +- **It searches titles, not messages.** Message bodies are stored encrypted and are not indexed, so a phrase from inside an answer will not find the thread. Search for what the conversation was about instead. +- **It does not hide archived or temporary chats.** Either can appear in results even though neither is listed in Recents. + +This palette belongs to Chat; Cortex Code has its own on the same keys. + +## Find something inside the open conversation + +Open **Search in this conversation** and type into **Search this conversation**. A counter shows which match you are on out of how many there are. **Previous match** and **Next match** step through them, as do Enter and Shift with Enter. **Clear search** empties the field and **Close search** puts the bar away; Escape does both in turn, clearing first and closing on a second press. + +If there is nothing to find you get **No matches in this conversation.** and a useful hint: **Try a shorter word, or a term from the answer rather than the question.** + +## Temporary chats + +A temporary chat is for a question you do not want to keep. + +| Behaviour | Detail | +| --- | --- | +| Where it appears | Not listed in Recents | +| Memory | Neither read nor written | +| Lifetime | Deleted after 30 days | +| Pin and Move | Hidden for this chat | + +Start one from the `/` palette or the composer's **Temporary chat** toggle, before the first message. The choice is fixed at that point: **Temporary is chosen when a chat starts.** You cannot make a normal chat temporary afterwards, and you cannot promote a temporary chat into a permanent one. A **Temporary** badge in the header tells you which kind you are in. Filing one into a project is refused with **A Temporary chat cannot be filed into a project.** + +## Not available yet + +Three things people reasonably look for do not exist in Chat today. + +- **Renaming a chat.** Titles are generated and cannot be edited. +- **Exporting a whole conversation.** There is no control for it. What you can export is a single answer, as a deck; see [Export documents](/chat/document-export). +- **Sharing a conversation.** The **Share** control does not produce a link, and Chat has no shared threads. **Copy link to message** gives you a link that opens the conversation at one message for anyone who already has access to it, which on a per-account product means you. See [Sharing and teams](/chat/sharing). + +## Shortcuts + +| Keys | What it does | +| --- | --- | +| Cmd or Ctrl with K | Open Chat search | +| Cmd or Ctrl with / | Open the shortcut sheet | +| Escape | Stop the answer being written | +| Cmd or Ctrl with Shift and E | Archive the current chat | +| Cmd or Ctrl with Shift and Backspace | Delete the current chat | + +The last two work but are not printed on the shortcut sheet. The full list for every product is on [Keyboard shortcuts](/getting-started/keyboard-shortcuts). + +## Related + +- [Chat quickstart](/chat/quickstart) - your first conversation, step by step. +- [How Chat works](/chat/how-it-works) - what one turn does, and what is stored. +- [Models and thinking](/chat/models) - why the model is fixed once a chat starts. +- [Projects](/chat/projects) - file related chats together under shared instructions. +- [Sharing and teams](/chat/sharing) - what you can hand to someone else today. diff --git a/chat/data.mdx b/chat/data.mdx new file mode 100644 index 0000000..a7dd623 --- /dev/null +++ b/chat/data.mdx @@ -0,0 +1,80 @@ +--- +title: "Cortex Data" +description: "Connect a business-metrics source to your account, ask metric questions in a chat, and pin a chart on the thread." +icon: "chart-line" +--- + +**Cortex Data** connects a business-metrics source, the place your revenue, charges and subscriptions already live, to your Cortex account. Once it is connected you can ask metric questions in an ordinary chat and get an answer computed from your own numbers, and you can keep the chart it draws as a block on the thread. + +It appears as the **Data** card at the top of the **Connectors** page, described there as `Ask about connected business metrics and pin a chart on the thread.` This page covers connecting it, choosing where it is available, the questions it can answer, the two accuracy rules worth knowing before you quote a figure, and what each connection state means. + +## Connect Data + + + + Data sits above the connector catalogue. On a deployment where no metrics source is configured there is no **Connect Data** control at all, which is the honest signal that the feature is not set up rather than broken. + + + Signing in happens with the provider you already use for your billing data, on the provider's own page. The connection is made with your own account. Cortex never sees your password. + + + Under **Where Data is available**, turn it on for **Chat**, for **Code**, or for both. At least one is required: the rule on the card reads `Data has to stay available to Cortex Chat, Cortex Code, or both.` and turning off the last one answers `Choose at least one`. + + + +While the sign-in comes back you see a short **Connecting Data** screen and then **Finishing…**. If you close the provider's page instead of approving it, you get `The connection was cancelled` with `Nothing was connected. You can try again from Connectors.` If the sign-in itself did not complete, the message is `The connection did not finish`, again with nothing connected. Both offer **Back to Connectors**. + + +Connecting Data needs a signed-in account. A guest is refused before anything is created, because a guest session cannot be signed back into to revoke the connection later. + + +## Where Data can be used + +| Surface | Availability | +| --- | --- | +| **Cortex Chat** | Yours to choose, shown as a chip with `on` or `off`. | +| **Cortex Code** | Yours to choose, on the same terms. The planning modes of Code do not receive it. | +| **Cortex Bot** | Not offered. Data is not a Bot surface. | + +Where only one surface is on, the card carries the shorthand badge `Chat only` or `Code only`. Change the surfaces by pressing the chips on the connected card; there is nothing to sign in to again. + +## Ask a metric question + +With Data on for Chat, ask in plain language: what charges looked like last quarter, what the current annual recurring revenue is, how this month compares with the last one. Three things can happen in a turn. + +- **Look up a metric.** Revenue, successful charges or subscriptions over a window. +- **Investigate a metric.** The same figure plus the period before it, so the answer has something to compare against. +- **Write a dashboard.** The chart is pinned onto the conversation as a block that stays on the thread, rather than a picture you have to ask for again. + +For charges the windows offered are the **last 30 days**, which is the default, **this quarter**, and **this year**. Long result sets are paginated, and past a large number of pages the answer is marked as truncated rather than quietly cut short. + +While a chart is being drawn the block reads `Preparing the chart…`. A finished chart labels each point as `{label}: {value}` and carries a `Source` line back to where the figures came from. Where the figures arrived but cannot be plotted you get `No series to plot.`, and where the drawing itself failed, `The chart could not be drawn.` In both cases the numbers in the answer stand; it is the picture that is missing. + +## Two rules that keep the numbers honest + + +**Annual recurring revenue is computed from active subscriptions**, annualised. It is not a sum of past charges relabelled as recurring revenue, so it will not match a charges total for the same window, and it is not supposed to. + +**A book of business in more than one currency is refused, not totalled.** Cortex will not add two currencies together and present the sum as a figure. A zero-amount row in another currency does not trigger this. + + +## Connection states + +| State | What you see | What to do | +| --- | --- | --- | +| Unavailable | No **Connect Data** control | Nothing. Data is not set up on this deployment. | +| Not connected | The **Connect Data** button | Connect it. | +| Connected | `Connected`, or `Connected as {label}`, with the surface chips | Nothing. | +| Needs reconnect | **Reconnect** | Sign in again with the provider. | + +**Disconnect** turns Data off everywhere and removes the connection. When an action cannot be completed, the product names which one it was: `Data could not be connected`, `Data could not be updated`, or `Data could not be disconnected`. Nothing is half-applied. + +There is no published per-day allowance for metric questions. Where a limit applies on your plan or your deployment, the turn tells you at the point it stops. + +## Related + +- [Connectors](/chat/plugins) is where the Data card and every connected app live. +- [Built-in tools](/chat/tools) covers the other tools a Chat turn can call. +- [Cortex Code](/code/index) is the other surface Data can be turned on for. +- [Chat canvases](/chat/canvases) covers the other kind of block that stays on a thread. +- [Chat troubleshooting](/chat/troubleshooting) covers turns that stop without an answer. diff --git a/chat/deep-research.mdx b/chat/deep-research.mdx index 1dce74e..68be967 100644 --- a/chat/deep-research.mdx +++ b/chat/deep-research.mdx @@ -1,67 +1,114 @@ --- title: "Deep Research" -description: "Plan the questions, read live sources, and write a cited report. A Chat feature — not a Code tool and not a Bot skill." -keywords: ["research", "citations", "sources", "report"] +description: "Plan the questions, read live sources, and get a report with numbered citations you can open in a reader and save to Library." +icon: "magnifying-glass-chart" --- -Deep Research turns a conversation into a research run. Instead of one answer, Cortex plans a set of questions, reads live sources for each in parallel, and writes a report with citations. You review the plan before it runs and read the report on the thread when it is done. +**Deep Research** turns one question into a research run. Instead of a single answer, Cortex Chat writes a plan, reads live sources for each question in parallel, and produces a report whose sentences carry numbered citations. It is worth the wait when the answer has to be defensible: a market scan, a comparison, a timeline, anything you will forward to someone who will ask where a number came from. - - Chat composer prefilled with “Research the latest on” and the model chip showing Deep Research enabled - +The run has three phases, and you are in control between the first and the second. This page covers turning it on, reviewing and editing the plan, scoping which sources may be cited, what you can do while it runs, how to read the report and its citations, saving it as a file, and the limits. ## Turn it on -Either: +Open the model chip's panel under the composer and switch on **Deep Research**, listed under the **THINKING** heading as `Plan the questions, read live sources and write a cited report.` While it is on, the chip's detail line reads `· Deep Research`. -- Open the model chip under the composer and switch on **Deep Research** — *Plan the questions, read live sources and write a cited report.* -- Choose the **Research** card on Chat home. It prefills *Research the latest on* and enables Deep Research for that conversation. +From an empty Home screen, the **Research** app card does the same thing and seeds the ask for you. Then describe what you want to know. The more specific the ask, the sharper the plan. -## The run +## Review the plan - - - Cortex proposes the questions it will answer. The plan appears as a research block on the thread. Review it; a plan that has not been run still offers **Start** when you come back to the thread later. - - - Choose **Start**. Each question runs as its own background child, in parallel with the others, fetching and reading sources. **Start** disappears once the run has begun. - - - The report lands on the thread with its citations. Plan and report persist as research blocks, so you can return to them, ask follow-ups, or start a plan from the conversation. - - +Nothing is searched until you say so. Cortex first writes a **Research plan** on the thread: a **Plan title**, a numbered list of **Research questions**, a labelled **Outline**, and a small **Plan diagram** of the approach. -## Limits +- Edit any question in place, or use **Add a question** and type into `Another question`. A counter reads `{count} of {max} questions`. +- Remove questions you do not care about. Fewer, sharper questions beat a long list. +- The plan survives a page reload, so you can leave it and come back. +- When you are happy, choose **Start research**. The plan disappears from the thread once the run begins. + +## Scope it with Trusted sources + +**Trusted sources** is the scoping control, and its own line explains the rule: `Only these hosts, connected apps, and project files are cited. Leave hosts empty to search the open web.` -| Cap | Limit | +| Field | What it does | | --- | --- | -| Questions per run | 32 | -| Sources per run | 80 | -| Questions in parallel | 8 | -| Fetches per question | 4 | -| Time per question | 180 seconds | +| **Allowed hosts** | Hostnames the run may cite, for example `example.com`. Leave it empty to search the open web. | +| **Project files** | Folds a project's files and instructions into the run. | +| **Trusted domains** | The list as it stands for this run. | -A research run has its own loop and its own limits. It does not inherit Chat's eight-round tool budget, and it does not draw tool-start / tool-end chrome for every fetch. +Hostnames only, and at most five. A URL is not a hostname, and the refusals say so: `Use hostnames only — not URLs, IP addresses, or more than five names.` If you have narrowed the list to nothing you get `Add at least one hostname before starting. An empty list does not search the web.` -## Where Deep Research lives +You can also say that no connected app should be consulted. Where you have none attached to Chat, the panel reads `No connected apps on Chat.` -| Surface | Available? | -| --- | --- | -| Cortex Chat | Yes — the toggle in the model chip | -| Cortex Code | No. Code has web fetch inside a session, not Deep Research. | -| Cortex Bot | No. Bot has `web_search` and `web_fetch` tools, not a research skill. | -| CLI | No. `cortex scrape` fetches a single page; `--search` enables web search in a session. | +When a run was scoped, the report tells the reader: `Citations are shown only when they match the trusted domains for this run.` + +## While it runs + +Progress is a short status line, not a wall of tool rows. **Research progress** moves through `Queued`, `Searching`, `Reading`, and then `Done` or `Failed`, and the line beside it uses a small fixed vocabulary: `Planning the research`, `Searching the web`, `Reading sources`, `Checking {topic}`, `Filling gaps`, `Writing the report`, `Checking connected apps`. The eyebrow above the block reads `Deep Research · Running`. + +Two controls are yours while it works: + +- **Stop** ends the run. +- **Write with what you have** tells Cortex to stop searching and write the report from what it has already found. Use it when the status line has been grinding through the long tail of a question you no longer need. + +Several questions are worked on at once, and tools that would *write* anything are never used during a research run. + +## Read the report -## Tips +The finished report is ordinary Chat text with **numbered citations**, under the eyebrow `Deep Research · Report`. Each citation carries the page's title, its domain, and the sentence it supports, and the **Sources** list is grouped into `Web`, `Connected apps` and `Project`. Every report ends with the disclosure sentence, `This report was generated by Cortex Chat Deep Research.` -- Ask for the shape you want back: *a comparison table*, *a timeline*, *a one-page brief with sources*. -- Attach documents to the same thread when your question depends on them; the run can read Library attachments alongside live sources. -- For a quick factual answer, leave Deep Research off — a normal turn with web search is faster. +**Open reader** opens the report on its own, away from the thread, and **Follow up** takes you straight back into the chat with it in hand. **Close report** returns you to the conversation. + +Where a run cited nothing you see `No sources were cited.` or `No sources recorded for this report.` rather than an invented list. + +## Save the report as a file + +The report card carries an **Export** menu with four items: `Markdown` (`.md`), `PDF`, `Word` and `Deck`. + + +Each format stays disabled until the server reports it as available, and the card starts with all four off. On a deployment that has enabled none of them you get no options rather than an empty file, so do not count on a download being there. **Markdown** is the one format that is implemented today. PDF, Word and Deck are listed but answer `This format is not available yet.`, and the menu's own footer says so: `Markdown is ready now. Other formats stay listed until they ship.` + + +When an export does run, it saves into your [Library](/chat/library) rather than downloading to your machine, confirmed with `Saved to Library as {filename}.` and findable under the Library's **Reports** filter. The report card shows **In Library** once it is there. + +Two more conditions apply. Export stays off until the report cites at least one source, `Export stays off until this report cites at least one source.`, and a guest is asked to sign in first, `Sign in to export this report.` Exports also draw on a daily allowance that depends on your plan; see [Export documents](/chat/document-export) and [Plans and quotas](/getting-started/plans). + +## Limits + +| Limit | Value | +| --- | --- | +| Questions per plan | 32. A 33rd is refused | +| Sources per run | 80 | +| Questions worked in parallel | 8 | +| Page fetches per question | 4 | +| Time per question | 180 seconds | +| Report length | a budget of about 6,000 tokens | +| Trusted hosts | at most 5, hostnames only | +| Export formats implemented | Markdown only | + +Deep Research runs on a Chat conversation. It is refused on a Cortex Code conversation, where the tools are a session's own. Guests may run it, though they cannot export the result. + +## When it cannot run + + + + The run could not get out to the open web at all. Retry. If it persists, check [status.cortex.foundation](https://status.cortex.foundation). + + + The reader could not fetch the report. Return to the thread, where the report block itself is still there, and open it again. + + + You chose PDF, Word or Deck. Choose **Markdown**, the format that is implemented. + + + Check that the report cites at least one source and that you are signed in. Both turn the menu off. + + ## Related -- [Models](/chat/models) — the chip where the toggle lives. -- [Plans](/chat/plans) — turn the report into a task list. -- [How Chat works](/chat/how-it-works) — the ordinary tool loop that Deep Research replaces. +- [Models and thinking](/chat/models) - the chip panel where Deep Research is switched on. +- [Built-in tools](/chat/tools) - the ordinary tool loop a research run replaces. +- [Library](/chat/library) - where an exported report is saved. +- [Export documents](/chat/document-export) - the formats Chat can produce and the daily allowance. +- [Connectors](/chat/plugins) - connected apps a run may consult and cite. +- [Planning](/chat/plans) - turn a report into a task list. diff --git a/chat/document-export.mdx b/chat/document-export.mdx new file mode 100644 index 0000000..cfd2c68 --- /dev/null +++ b/chat/document-export.mdx @@ -0,0 +1,109 @@ +--- +title: "Export documents" +description: "What a chat can turn into a file: a deck built from an editable outline, the formats a research report can offer, and a CSV from a table." +icon: "file-export" +--- + +An answer is useful in the conversation, but a file is what you send to someone. From a chat, the export Cortex offers is a **deck**: it reads the thread, drafts an outline of slide titles and bullets, lets you edit every line, and only then typesets a file and saves it to [Library](/chat/library). + +This page covers the deck export a chat offers and the two ways into it, the plain CSV download under a table in an answer, the extra formats a Deep Research report lists and which one of them works today, the disclosures Cortex writes into the file itself, and how many exports a day each plan gets. + + +From an ordinary answer, a deck is the only file a chat produces. Other document formats appear only on a Deep Research report card, where Markdown is the one implemented today. There is also no control anywhere in the app that exports a whole conversation as a document. + + +## Export happens in two steps + +Nothing is written until the second step, and the split matters for your allowance. + +1. **Outline.** Cortex reads the thread and drafts slide titles and bullets. Every title and every bullet is editable. This step does not spend an export. +2. **Create.** Cortex typesets the file and saves it to Library. This step spends one export. A malformed outline is refused before anything is charged, and if the writer fails the export is returned to you. + +## Export an answer as a deck + + + + On the answer, choose **Export**. The dialog is titled **Export** and explains: `Review the outline before anything is created.` + + + It opens on `Drafting the deck outline…`, then shows the **Deck outline** heading with the number of slides it drafted. + + + Each slide has a title field and a bullets field, whose placeholder is `One bullet per line`. Rewrite anything you do not like, and delete what you do not need. + + + Under **Theme**, choose `Cortex` or `Cortex · Plain`. + + + Press **Create deck**. The dialog counts the slides as it writes them, then finishes with a result line naming the artifact, the slide count and the theme. The file is in Library. + + + +Pressing Escape cancels while you are still reviewing: the dialog states it itself, `Escape cancels before Create. There is no Slides tab.` If creation fails, the message is `The deck could not be created`. + +### Themes and slide layouts + +| Theme | How it looks | +| --- | --- | +| `Cortex` | cream page, dark ink, a teal accent bar | +| `Cortex · Plain` | white page, black ink, no accent bar | + +The outline can use these layouts: `Cover`, `Section`, `Bullets`, `Two-column`, `Table`, `Chart`, `Image` and `Sources`. + +## Export the whole thread as a deck + +The transcript header has its own entry point, **Export as deck**, which outlines the conversation rather than one answer. Its description reads `Outline the thread, preview the slides, then typeset a file into Library.` + +Press **Draft outline**. The panel shows `Drafting the outline…`, then the outline to review, with the reassurance `Cortex drafts an outline from this thread. Nothing is written until you download.` Confirming moves it to `Writing the deck…`, and on success you get a line reading `Saved to Library as` with the file name. From there, **Download** puts a copy on your machine and **Re-export** writes it again. + +Three messages worth recognising here: + +| Message | What it means | +| --- | --- | +| `Export this thread as a deck once there is something to outline — or draft from the title.` | the thread is still empty; ask something first | +| `The document writer is not available on this deployment.` | this deployment cannot typeset files; **Try again** later, and nothing was charged | +| `The deck could not be exported.` | the write failed; retry, and your export is returned | + +## Download a table as a CSV + +When an answer contains a table, the link under it reads **Export as spreadsheet**. Clicking it downloads a file named `table.csv` immediately. + +This is a browser-side download built from the table you can see, and it behaves nothing like the deck export. There is no dialog, no outline, no export allowance spent, and nothing is saved to Library. The file is comma-separated text, not a spreadsheet workbook, so a spreadsheet application will open it but formatting and formulas are not part of it. + +## Formats on a Deep Research report + +A Deep Research report card is the one place in Chat that offers a choice of document formats rather than a deck alone: `Markdown`, `PDF`, `Word` and `Deck`. **Markdown** is the one that works today, and the menu's own footer says so: `Markdown is ready now. Other formats stay listed until they ship.` Each item also stays disabled until the server reports it as available, so a report with no sources turns them all off. + +The research report card also has its own deck flow, whose wording differs slightly from the one on an answer: the title is **Export as a deck**, the hint reads `Review the outline, then Cortex typesets the slides. This is an export, not a separate generator.`, the confirm button is **Export deck**, and it shows `Writing slides…` while it works. If the capability is not ready you get `Deck export is not available yet.`, and if the outline cannot be drafted, `The outline could not be drafted.` + +See [Deep Research](/chat/deep-research) for what a report is and how to run one. + +## Disclosures travel inside the file + +Cortex writes its notices into the exported document rather than displaying them beside it, so they stay with the file when it is forwarded. Under **Disclosures** you may see that the document was drafted by a model and that Cortex writes that notice into the file itself, that it was made in a Cortex conversation and that the conversation is not in the file, that no human has reviewed it before it left Cortex, and image credits where they apply. The group ends with the point of the whole arrangement: `This notice is written into the file and travels with it.` + +## Exports per day + +Exporting is metered per day, per account. + +| Plan | Exports per day | +| --- | --- | +| Guest | 2 | +| Free | 15 | +| Go | not published | +| Plus | 100 | +| Pro | unlimited | + +You do not need an account to export, and drafting an outline never counts. Only creating the file does, and a failed write is refunded. When you run out, the plan-limit message says you have used today's document exports. No allowance is published for the Go plan yet, so treat it as unconfirmed rather than unlimited. See [Plans and quotas](/getting-started/plans) and [quota_exceeded](/problems/quota_exceeded). + + +Saving an exported file straight to a connected drive is not available yet. The button, its consent dialog and the revoke control all exist, but the save is refused in this wave. Download the file and upload it yourself. See [Sharing files and connected drives](/chat/library-sharing). + + +## Related + +- [Library](/chat/library) for where exported files are saved. +- [Deep Research](/chat/deep-research) for reports and their format options. +- [Chat canvases](/chat/canvases) for drafting a document in the conversation instead. +- [Sharing and teams](/chat/sharing) for what you can pass to another person today. +- [Chat troubleshooting](/chat/troubleshooting) for the export failure messages in context. diff --git a/chat/how-it-works.mdx b/chat/how-it-works.mdx index b12a524..13be48d 100644 --- a/chat/how-it-works.mdx +++ b/chat/how-it-works.mdx @@ -1,68 +1,115 @@ --- title: "How Chat works" -description: "A Chat turn is one tool-calling loop: the model asks for tools, Chat runs them, results flow back, and the loop ends when the model stops." -keywords: ["tool loop", "context", "compaction", "rounds"] +description: "A turn is one message plus everything Cortex does to answer it: tools, citations, compaction, what is stored, and where the limits sit" +icon: "diagram-project" --- -A Chat turn is a real tool loop. The model emits tool calls, Chat executes them, the results re-enter the context, and the loop continues until the model stops or Chat reaches its round budget. What you see is the streamed result of that loop: tokens, then tools, then the finished reply. +A **turn** is one message from you plus everything Cortex does to answer it. Inside a turn the model can call tools, and every call and its result appear in the transcript as a row, so the work is visible rather than hidden behind a spinner. The loop is bounded, and knowing those bounds explains most of what you will see in a long or complicated answer. - - A Chat reply with headings and formatted prose explaining merge sort - - -## What you see - -1. You send a message, optionally with Library attachments. -2. The composer reads **Cortex is responding…** and the send button becomes a stop control. -3. Tokens stream. Tools may run. Their results come back into the thread. -4. The model stops, or Chat hits its budget of **eight tool rounds**. That budget is Chat's own — Code and Bot have different stopping rules. +This page is for readers who want to know what is actually happening between pressing Enter and reading an answer: what goes into a turn, in what order, what is kept afterwards, and what happens when a conversation grows too long to send. ## What goes into a turn -| Input | Source | +| Input | Where it comes from | | --- | --- | | Your message | The composer | -| Attachments | [Library](/chat/library) files, never a pasted URL | +| Attachments | Files you attach, which land in [Library](/chat/library) | | Standing instructions | The [project](/chat/projects) the chat belongs to | -| Preferences | [Memory](/chat/memory) | -| Model and thinking level | The [composer chip](/chat/models) | -| Tools | Built-in tools, connected apps enabled for Chat, and your MCP servers | +| Standing preferences | [Memory](/chat/memory), unless the chat is temporary | +| Model and thinking level | The [model chip](/chat/models), fixed when the chat starts | +| Tools | [Built-in tools](/chat/tools), your [connectors](/chat/plugins) and your [MCP servers](/chat/mcp-servers) | + +Once everything is assembled, Cortex clamps the answer so that the prompt and the output together fit inside the model's context window. + +## The order of events + + + + The message is counted against your allowance and committed before a single word is written, which is why a request that gets refused costs you nothing. If generation then fails after being charged, the allowance comes back and you see **Generation failed. Your allowance for this message has been returned.** + + + Your message is saved to the conversation, and the turn begins. + + + The answer is produced by Cortex and buffered as it is created, before any of it reaches your browser. That is the reason a dropped connection or a page reload does not lose an answer in progress. + + + Words, thinking, tool rows, citations and file cards arrive as they are ready rather than in one block. See [Streaming and reconnects](/chat/streaming). + + + A turn ends because the model finished, because it hit its output ceiling, because you interrupted it, or because it failed. Each of those leaves a different card in the transcript. + + + +Only one live answer can exist in a conversation at a time. While a turn is running, regenerating an answer or editing an earlier message is refused with **Wait until the current answer finishes.**, because either one would put a second live answer into the same thread. + +## What you see while it runs + +| On screen | What it means | +| --- | --- | +| Words appearing a few at a time | The answer is being written now | +| A **Thinking** block, collapsing to a line with a duration | The model reasoned before answering. Some turns record none, and the block says so | +| A one-line row such as *Searched the web* | A tool ran. The row then shows how it ended | +| A numbered citation with a source | The claim above it came from that source | +| A file card | Cortex produced a file. It is in Library | +| A short notice on the answer | Cortex added a safety or disclosure note | +| A marker saying earlier messages were summarised | Compaction happened, see below | +| **Reconnecting** | The connection dropped and is being re-established | -After assembly, Chat clamps generation so prompt plus output fit the model's context window. +A tool row's label is deliberately short and human. A long tool result is shortened for display, and the row says how much was cut. -## Tools the model can receive +## The limits of one turn -| Group | Tools | +| Limit | Value | | --- | --- | -| Information | `web_search`, `web_extract`, `current_time` | -| Computation | `python` — a small snippet sandbox | -| Media | `generate_image`, `detect_image` | -| Documents | canvas tools, `read_artifact`, `grep_artifact` | -| Context | memory tools, `skill_view` | -| Design | `design_write`, `design_read` — host a Design canvas from Chat | -| Yours | Connected apps enabled for **Chat**, and the account's MCP servers | +| Characters in one message | 50,000 | +| Tool rounds in one turn | 8 | +| Tool calls in one turn | 50 | +| Identical repeated calls tolerated | 6 | + +None of these fail silently. + +- When the round budget runs out, the model is told the budget is exhausted and asked to answer with what it already has, or to ask you how to proceed. +- When the same call repeats six times without getting anywhere, the loop is broken with **The same tool call repeated without progress. Try a different action.** +- A message over the character ceiling is refused with **The message is longer than the permitted maximum.** Split it, or attach the text as a file. + +Eight rounds is Chat's own budget, chosen for a conversation. [Cortex Code](/code/how-it-works) allows 48, because working through a repository takes more steps than answering a question. [Deep Research](/chat/deep-research) runs its own loop with its own caps and does not spend Chat's eight rounds. -Chat's `python` runs a snippet in an untrusted sandbox with no workspace. It is not Code's shell inside a Cloud guest, and it cannot see a repository or a Bot's desktop. See [Security](/security/overview). +## When a conversation outgrows the model -## Compaction +A long thread eventually holds more than can be sent to the model. Rather than quietly dropping the beginning, Cortex summarises the earliest messages into a single summary and carries on. A marker appears in the transcript where that happened, saying how many earlier messages were summarised to make room. You keep seeing the original messages; the summary is what the model reads in their place. -Long threads are compacted on the request path so they keep fitting the model. Compaction keeps the last user ask, the active research plan, open artifact ids, and research child ids. It **fails closed**: if the summariser is unavailable, the turn returns [`service_unavailable`](/problems/service_unavailable) rather than silently dropping old turns. +Compaction happens on whichever of these comes first, and also before a task returns a result and before a Deep Research synthesis: -## Deep Research is a different loop +| Trigger | Threshold | +| --- | --- | +| Estimated context | 24,000 tokens | +| Transcript size | 64,000 characters | +| Turns in the conversation | 12 | + +Some things are never summarised away: your own messages, the last question you asked, the active plan, open tasks, open files and your memory profile. Compaction fails closed, so if that set cannot be preserved, nothing is compacted at all instead of something being lost. A conversation holds one summary at a time, and a later compaction replaces the earlier one. + +## What is kept + +| Kept | Not kept | +| --- | --- | +| Your messages and the answers, stored encrypted | A dictated clip, once it has been turned into text | +| Attachments, in Library | The message text in any search index, so search reads titles only | +| Canvases attached to the conversation | The title in the link, which always stays an identifier | +| The conversation title | | -A research run plans questions and fans out to parallel children with its own caps. It does not use the eight-round budget and does not draw tool chrome for each fetch. See [Deep Research](/chat/deep-research). +Because message bodies are stored encrypted and never indexed, [Chat search](/chat/conversations) matches conversation titles rather than what was said inside them. -## Compared with Code and Bot +Temporary chats are the exception to all of this: they are not listed in Recents, they neither read nor write memory, and they are deleted after 30 days. -| | Chat | Code | Bot | -| --- | --- | --- | --- | -| Loop stops when | The model stops, or 8 tool rounds | The model stops, or the turn is cancelled | The model stops, a 15-minute deadline, or six identical tool calls in a row | -| Code runs in | A snippet sandbox | The session's Cloud guest (or This PC / SSH) | The bot's computer | -| Transcript | Streamed reply with tool results | A turn timeline | User-visible bubbles only | +## Why an error can appear inside a good answer -See [How Code works](/code/how-it-works) and [How Bot works](/bot/how-it-works). +By the time something fails, the response has usually already started. The failure therefore arrives as part of the answer rather than as a refusal before it, which is why an answer can begin normally and then show an error card partway down. The card carries a code, and every code has a page under [Problems](/problems). If the answer stopped rather than failed, **Continue** picks it back up where it left off. ## Related -- [Streaming](/chat/streaming) — reconnects and run state. -- [Models](/chat/models) — context windows and thinking levels. +- [Streaming and reconnects](/chat/streaming) - what a dropped connection does to a live answer. +- [Conversations](/chat/conversations) - stop, edit, regenerate, branch and version an answer. +- [Models and thinking](/chat/models) - the two models and the three thinking levels. +- [Built-in tools](/chat/tools) - what the tool rows in a turn actually did. +- [Chat troubleshooting](/chat/troubleshooting) - the messages a failed turn leaves behind. diff --git a/chat/image-generation.mdx b/chat/image-generation.mdx new file mode 100644 index 0000000..ae8d53b --- /dev/null +++ b/chat/image-generation.mdx @@ -0,0 +1,95 @@ +--- +title: "Image generation" +description: "Ask Cortex Chat for a picture, follow the card as it generates, and find the finished image in your Library with its prompt and seed." +icon: "image" +--- + +Ask **Cortex Chat** for a picture in plain language and it writes the picture prompt for you before anything is generated. What comes back is a single card in the conversation that moves through its states, plus a file in your **Library** that keeps the prompt you typed and the seed that produced it. The image model is **Cortex-Image-1**. + +This page covers asking for a picture, reading the card, steering the size and the seed, where the finished file lands, how many images each plan includes per day, and the cases where nothing runs at all. + +## Ask for a picture + + + + Write what you want as a sentence rather than a list of keywords. You can attach reference files on the same turn: a Chat turn takes at most four attachments, and each file has to be within the 10 MB per-upload ceiling, which is the same for everyone whatever your plan. + + + The card first shows **Improving prompt…**, while Cortex turns your ask into a complete scene description, then **Generating image…** while the picture is made. + + + The tile fills with the picture and the caption gives the model name and how long it took, as `Cortex-Image-1 · {seconds}s`. Elsewhere the same result is labelled `Generated with Cortex-Image-1`. + + + +Asking for another picture adds a card instead of replacing the first one, so a run of attempts stacks down the thread in the order you asked for them. + +## What the card shows + +| State | What you see | +| --- | --- | +| Queued | The caption `Improving prompt…` and a small spinner, with no tile yet. | +| Generating | The tile with a progress ring and the caption `Generating image…`. | +| Done | The picture, with `Cortex-Image-1 · {seconds}s` under it. | +| Error | `The image couldn't be generated.`, the line `Nothing was counted.`, a short code and request id, and **Retry**. | + +**Retry** re-runs whichever step failed, the prompt rewrite or the generation. Where neither can be re-run, the button is absent rather than present and dead. + +A card that reads done means the generation finished, not that the picture has painted: the tile fills once the file arrives from your Library. Closing the conversation settles any generation still in flight. + +## Steer the result + +You can set the following on the ask itself. + +| Control | What it does | +| --- | --- | +| Size | One of four shapes: square `1024x1024`, landscape `1792x1024`, portrait `1024x1792`, or a small square `512x512`. | +| Seed | Any number from zero upwards. The same prompt with the same seed gives you the same picture again. A negative seed is refused before any allowance is touched. | +| Things to avoid | What you want kept out of the frame. | +| Steps | 1 to 50. More steps means more detail and more time. | +| Guidance | 0 to 20. How closely the picture follows the prompt. | + +Cortex gives the prompt rewrite about 45 seconds and the generation itself about two and a half minutes. Past that the card reports the error instead of waiting indefinitely. + +## Where the image lands + +The finished picture is saved to your **Library** as a generated file, and it does not spend your per-upload allowance the way an upload does. From there you can reuse it in another chat or attach it to a project. + +The card and the Library keep the picture's provenance: **the prompt you typed** and **the seed**, never the rewritten prompt Cortex generated from it. + +- **Image history** on the card shows the prompt, the seed, the size and the date. +- **Reuse seed** puts the prompt and the seed back in the composer, so you can change one thing and try again rather than generating from the dialog. + +## Included images per day + +Image generation is metered per day, and the allowance depends on your plan. The Go plan's figure is not published, so this page will not invent one: check **Settings → Plan & billing** on a Go account for what it allows. + +| Plan | Included images per day | +| --- | --- | +| Guest | 2 | +| Free | 15 | +| Go | Not published | +| Plus | 100 | +| Pro | Unlimited | + + +When a generation fails, nothing is counted. The card says so, and where the allowance is known it says how much is left, as `Nothing was counted — {remaining} of {limit} included images left today on {plan}.` The prompt rewrite spends the allowance before the generation runs, which is exactly why a failure has to give it back. + + +When the day's allowance is gone, the turn stops with [`quota_exceeded`](/problems/quota_exceeded) rather than generating a lesser picture. + +## When nothing runs + +- **A web address in the prompt.** A prompt that contains a link is refused before either step. Neither the rewrite nor the generation happens, and nothing is counted. Describe the reference instead, or attach the file. +- **An attachment the turn cannot read.** PNG, JPEG, WebP, GIF, PDF, JSON and ordinary text types are accepted; HTML, XML and JavaScript are not, and SVG is refused. +- **A deployment without image generation.** Where the image stack is not configured, the tool is simply not offered in the turn. + +A generated picture is an ordinary Library file. If you want to know whether a picture reads as camera-made or generated, that is a separate ask: see [Origin check](/chat/origin-check). It never runs by itself after a generation. + +## Related + +- [Library](/chat/library) is where generated pictures are kept. +- [Attachments and files](/chat/attachments) covers the per-turn and per-file limits. +- [Origin check](/chat/origin-check) answers whether a photo or clip is authentic. +- [Built-in tools](/chat/tools) lists what else a Chat turn can call. +- [Plans and quotas](/getting-started/plans) has the per-plan allowances in one place. diff --git a/chat/images.mdx b/chat/images.mdx deleted file mode 100644 index 7415e05..0000000 --- a/chat/images.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: "Image generation" -description: "Ask Chat for a picture and Cortex-Image-1 paints it. Generated images land in Library. On Free and Guest, images are a daily quota — not a paywall." -keywords: ["pictures", "Cortex-Image-1", "generation", "text to image"] ---- - -Ask for a picture in plain language, or choose **+ → Image** on the composer. Chat loads its image skill, turns your ask into a complete scene description, and calls **Cortex-Image-1**. The finished picture is a Library file you can reuse in any chat or project. - - - The composer + menu with Attach file, Image, and Check origin - - -## Ask for a picture - -Describe the whole scene — subject, setting, light, style. You can also set: - -| Option | Range | Notes | -| --- | --- | --- | -| Size | Preset sizes | Pick from the options offered | -| Seed | Any integer | Same seed, same prompt: a reproducible picture | -| Negative prompt | Free text | What to keep out of the frame | -| Steps | 1–50 | More steps, more detail, more time | -| Guidance | 0–20 | How closely the picture follows the prompt | - -## What the card shows - -| State | You see | -| --- | --- | -| `queued` | **Improving prompt…** — Chat is completing the scene description | -| `generating` | A skeleton where the picture will appear | -| `done` | The picture, saved to Library | -| `error` | An error square — never a spinner | - -If the Library fetch for a finished picture fails, you see the error square. If image generation is not configured on a deployment, the request fails closed before any quota is spent. - -## Quota, not a paywall - -On **Free** and **Guest**, image generation is metered as `images_per_day`. Using the window is [`quota_exceeded`](/problems/quota_exceeded): wait for the reset shown under **Settings → Plan & billing**. A plan that does not include image generation at all is [`entitlement_required`](/problems/entitlement_required). Free explicitly lists *Image generation with Cortex-Image-1*. See [Plans](/getting-started/plans). - -## About the model - -**Cortex-Image-1** is the image model for Cortex Chat, in preview, built on NVIDIA Cosmos. It appears in **Settings → Models** beside the chat models with the attribution *Built on NVIDIA Cosmos*. See [Models](/chat/models). - -## Origin check is separate - -A generated picture is a Library file like any other. **Check origin** is a different ask — attach media and ask whether it is authentic. It does not run automatically after every generation. See [Origin check](/chat/origin-check). - -## Tips - -- One complete sentence beats a list of keywords: *A lighthouse on a granite headland at dusk, long exposure, soft teal sky.* -- Reuse the seed to iterate on a picture you like while changing one thing at a time. -- Use the negative prompt for the things the model keeps adding that you do not want. - -## Related - -- [Models](/chat/models) — Cortex-Image-1 beside the chat models. -- [Library](/chat/library) — where generated pictures land. -- [Plans and quotas](/getting-started/plans) — how `images_per_day` behaves. -- [Origin check](/chat/origin-check) — ask whether a picture reads as generated. diff --git a/chat/index.mdx b/chat/index.mdx index e2eff6d..5ba09f8 100644 --- a/chat/index.mdx +++ b/chat/index.mdx @@ -1,140 +1,159 @@ --- title: "Cortex Chat" -description: "The conversation product at cortex.foundation — projects, Library, plans, models, tools, Deep Research, images, and how a turn runs." -image: "/images/banners/chat.png" -keywords: ["assistant", "conversations", "chat app"] +description: "The conversation product at cortex.foundation: streaming answers, attachments, projects, research, and a map of every Chat page" +icon: "comments" --- -Cortex Chat is the assistant for research, writing, and everyday questions. It streams answers as they are written, keeps documents and threads together in projects, and hands off to Code or Bot when the job is a repository or a computer rather than a conversation. +Cortex Chat is the conversation product at [cortex.foundation](https://cortex.foundation). You ask a question, Cortex writes the answer while you watch, and everything it produces on the way stays with your account. It is the place to start for research, writing, analysis and everyday questions, and it points you at the other Cortex products when the job is a repository or a machine rather than a conversation. -Chat works before you sign in. Projects, files, memory, plans, and connections belong to a signed-in account. +Chat works before you sign in, with a smaller allowance and without uploads, projects or web search. This page describes the surface you land on, then links to every other page in the Chat tab. - - Cortex Chat home in the dark theme - +## The page you land on -## Start here +The home page greets you with **Good morning**, **Good afternoon** or **Good evening**, and shows a short list of starting points under the heading **Things Cortex does well.** - - - First message, attach a file, pick a model, keep the thread in a project. - - - Standing instructions, chats, and files kept together. - - - Built-in tools, connected apps, GitHub, and MCP servers. - - - -## Finding your way around - -The sidebar holds everything Chat can open. Three of its entries are worth knowing before you start clicking. +| Starting point | What it says | What it does | +| --- | --- | --- | +| **Code** | *The Cortex agent working inside your repos.* | Points at [Cortex Code](/code) | +| **Research** | *Cited answers from live sources.* | Prefills the composer with a research request | +| **Science** | *Cited literature with provenance on the answer.* | Prefills a literature request that keeps citations on the answer | +| **Docs** | *Drafts that structure themselves.* | Prefills a document request | +| **Agents** | *Background runs on schedules.* | Points at [Cortex Bot](/bot) | -| Entry | What it opens | -| --- | --- | -| **Chat · Code · Bot** | The product switcher. Chat is the default; Code and Bot need a signed-in account. | -| **Projects** | Standing instructions plus the chats and files that belong together. See [Projects](/chat/projects). | -| **Artifacts** | Opens the [Library](/chat/library) — your uploads and everything the assistant produced. | -| **Customize** | **Connectors**: connect apps and choose whether each reaches Chat, Bot, or both. See [Tools](/chat/tools). | -| **Recents** | Your latest conversations. Guests see the current session only. | +Three example prompts sit below them: **Plan a 5-day trip to Tokyo**, **Summarize this quarterly report** and **Draft a launch announcement**. Under the composer, on every page, Chat repeats the line **Cortex is an AI and can make mistakes.** -**New chat** is an action, not a selected row. **Pinned** collects the projects you use most. +The composer itself is one text box labelled **Ask anything, or pick an app below…**, with **Attach a file**, **Deep Research**, **Science**, the model chip, and **Send message**. While an answer is being written the box reads **Cortex is responding…** and the send button becomes **Stop responding**. -### The composer +The sidebar has three sections: **WORKSPACE**, **PINNED** (drawn only once you have pinned something) and **RECENTS**. Sending your first message turns the home page into a conversation in place, so nothing reloads and nothing flickers. -- **+** opens **Attach file**, **Image**, and **Check origin**. -- The **model chip** — for example *Cortex 1 Mini · Preview · Thinking Low* — switches model, sets the Thinking level, and toggles **Deep Research**. -- **Enter** sends, **Shift + Enter** adds a line, **Esc** stops a response. -- While a turn runs the placeholder reads **Cortex is responding…** and the send button becomes a stop control. + +Chat offers two models today, **Cortex 1 Mini** and **Cortex Teutonic-1**, and both are marked **PREVIEW** in the picker. Neither depends on your plan. See [Models and thinking](/chat/models). + -### The four cards on Chat home +## Start here -They are shortcuts, not separate products. + + + From an open tab to a useful first conversation, in a few minutes. + + + What happens inside one turn: tools, citations, compaction, and the limits. + + -| Card | What it does | -| --- | --- | -| **Code** — *The Cortex agent working inside your repos* | Opens Cortex Code | -| **Research** — *Cited answers from live sources* | Prefills the composer and turns on Deep Research | -| **Docs** — *Drafts that structure themselves* | Opens a new chat with a document canvas beside it | -| **Agents** — *Background runs on schedules* | Opens Cortex Bot | +## Conversations -### A thread + + + Start, edit, branch, pin, archive, delete and search your threads. + + + The model chip, what Preview means, and the three thinking levels. + + + What you can attach, the size ceiling, and where uploads land. + + + Why an answer arrives in pieces, and what a dropped connection does. + + + Dictate a message, and hear an answer read back, where both are available. + + + A document beside the conversation that you and Cortex can both edit. + + + Turn an answer into a deck, and download a table as a spreadsheet file. + + -Every reply carries **Copy**, **Listen** (when voice is available), and thumbs up or down. The thread header offers **Start a plan** and **Move to project**. Replies render markdown — headings, tables, and syntax-highlighted code blocks with their own **Copy** button. +## Organize your work - - A Cortex Chat thread with a reply in the conversation pane - + + + Standing instructions, knowledge and chats kept together. + + + Everything you uploaded and everything Cortex produced. + + + Share a Library file, connect a drive, and attach items from it. + + + What Cortex remembers between chats, and how to review or delete it. + + + Task lists that outlive the conversation they came from. + + + Runs that happen on a schedule instead of while you wait. + + -## Core guides +## Research and creation - - Standing instructions, chats, and files kept together. Every chat in a project starts from its instructions. + + The tools a turn can call, and what their rows in the transcript mean. - - Everything you uploaded and everything the assistant produced. Files stay when a chat is deleted. + + Planned questions, live sources, and a cited report. - - Turn a long answer into steps you can tick off. Start one from any chat or from Planning. + + Ask for a picture, and see where it lands. - - Cortex 1 Mini, Cortex Teutonic-1, the Thinking level, and what happens at peak hours. + + Attach media and ask whether it is authentic. - - Built-in tools, connected apps, GitHub, and MCP servers — and which product each connection reaches. + + Ask metric questions and keep a dashboard on the thread. - - Chat is per account. What that means for projects, plans, and threads. + + Bundled and user-written skills, and how a turn loads one. -## Research and media +## Connected apps - - Plan the questions, read live sources, write a cited report. - - - Cortex-Image-1 from the composer. Quota, not a paywall, on Free and Guest. + + Connect an app and choose which products may use it. - - Ask whether attached media is authentic. Fails closed when it cannot run. + + Add a remote server and use its tools inside a turn. - - Dictate with the mic and hear answers with Listen — when the deployment supports them. + + Tools a web page offers, and the consent card in front of them. -## Context that carries over +## Reference - - Standing preferences and facts, reviewable and deletable one by one. + + Chat is per account. What that means, and what you can share today. - - A document sidecar beside the conversation, drafted by Cortex or by you. + + The messages Chat shows when something goes wrong, and what to do. -## When to switch -Chat does not run Code's workspace shell or Bot's computer. Chat's Python tool is a snippet sandbox with no workspace, and it cannot see a repository. +## How it fits with the other products + +Chat is a conversation. It has no workspace, no repository and no computer of its own, so three jobs belong elsewhere. -| Stay in Chat | Open Code | Open Bot | +| Stay in Chat | Open Cortex Code | Open Cortex Bot | | --- | --- | --- | -| Questions, writing, research, pictures, origin checks, documents, plans | A repository, an isolated Cloud guest, diffs, a pull request | An always-on teammate with a computer, routines, approvals | +| Questions, writing, research, documents, plans | A repository, a branch, a diff, a pull request | A teammate with a computer and runs on a schedule | -## Under the hood +Two connections are worth knowing. A note you save out of an answer lands in Library and is **Saved in Chat Artifacts. Available from Chat, Code and Bot.** And a Chat canvas is a plain text document attached to one conversation, which is not the same thing as a [Design canvas](/design/canvases). -- [How Chat works](/chat/how-it-works) — the tool loop, compaction, and Chat's round budget. -- [Streaming](/chat/streaming) — tokens, then tools, then the finished reply; what happens on a dropped connection. -- [Settings](/getting-started/settings) — theme, language, shortcuts, defaults, privacy. -- [Chat troubleshooting](/chat/troubleshooting) — messages that are not errors, and what to do next. +If you are not sure which product you want, read [Which product do I need?](/getting-started/choose-a-product). -## Next +## Related -1. [Chat quickstart](/chat/quickstart) — from an open tab to a useful first conversation. -2. [Projects](/chat/projects) — instructions your chats start from. -3. [Models and thinking](/chat/models) — pick a model per conversation. -4. [Tools and connectors](/chat/tools) — connect an app or an MCP server. +- [Chat quickstart](/chat/quickstart) - send a first message and get a real answer. +- [Conversations](/chat/conversations) - manage the threads you accumulate. +- [How Chat works](/chat/how-it-works) - the turn, its tools and its limits. +- [Plans and quotas](/getting-started/plans) - what your allowance covers. +- [Chat troubleshooting](/chat/troubleshooting) - when a turn, a file or a model misbehaves. diff --git a/chat/library-sharing.mdx b/chat/library-sharing.mdx new file mode 100644 index 0000000..33f2259 --- /dev/null +++ b/chat/library-sharing.mdx @@ -0,0 +1,101 @@ +--- +title: "Sharing files and connected drives" +description: "Share a Library file as a Viewer or Editor grant, copy a link, connect a cloud drive, and attach drive items without a second upload." +icon: "share-nodes" +--- + +Two things extend your [Library](/chat/library) outwards: **grants**, which let a named person see one of your files, and **cloud drives**, which let you browse a drive you already own and attach items from it without uploading them again. Both are built on the same rule, and the Library page states it in its own lead: sharing never moves ownership. + +This page covers inviting someone to a file, what **Viewer** and **Editor** can actually do, revoking access, what **Copy link** does and does not do, connecting and disconnecting a drive, and attaching a drive item to a chat. + +## Share a file with someone + + + + From the file's row actions in Library, choose **Share**. The dialog is titled **Share this file** and explains the choice: invite a viewer to the latest file, or pin the share to one version. + + + Type it under **Share with**, in the field that shows a placeholder address such as `name@company.com`. + + + Pick **Viewer** or **Editor**. + + + **Always latest** makes the share follow every restored version. **Pin version** freezes the share on the version you are looking at now, so the other person keeps seeing exactly what you showed them. + + + Choose **Send**. Library confirms with **File shared** and tells you whether the viewer follows the latest version or is pinned to one. + + + +An address the product does not recognise is rejected rather than silently invited, and a failed invite says so instead of appearing to have worked. + +## What a Viewer and an Editor can do + +| Action | Viewer | Editor | Owner | +| --- | --- | --- | --- | +| Open and download the file | Yes | Yes | Yes | +| Rename it | No | Yes | Yes | +| Delete it | No | No | Yes | +| Invite someone, change a role, revoke | No | No | Yes | +| Add it to a project as a source | No | No | Yes | + + +**Editor** grants renaming and nothing more today. There is no further write policy on a shared Library file yet, so do not count on an Editor being able to change a file's contents. + + +The uploader stays the owner of the file in every case. A grant is revocable at any time, and revoking it takes the file out of that person's **Shared with me** list. + +## Manage or revoke access + +Reopen **Share** on the file. **People with access** lists everyone you invited. Change someone's role with the role control on their row, or choose **Revoke** to end their access. When nobody else holds a grant, the dialog says so: nothing is shared, and ownership stays with you. + +## Copy link + +**Copy link** copies a link back to the file in your Library. It is not a public link. Whoever opens it still has to be signed in and still has to hold a grant on the file. There is no public token and no "anyone with the link" mode anywhere in Library, so a link that leaks does not expose the file. + + +A guest cannot create a grant, and cannot be the person you invite. The dialog says **Sign in to share**, and explains why: a guest session cannot be signed back into to revoke a grant later. See [Accounts](/getting-started/accounts). + + +## Connect a cloud drive + +A connected drive lets you browse and attach without re-uploading, and Chat cites the original item rather than a copy. + + + + The **Cloud drives** section lists the drives this deployment supports. + + + Sign in to the drive with your own account. Cortex shows a **Connecting a drive** screen while it finishes, then **Connected**. + + + The drive appears in the panel. Use **Search this drive** to find an item. + + + +If you decline the sign-in, Cortex says the connection was declined and that nothing was changed. If it fails part way, it tells you to try connecting again and, again, that nothing was changed. **Back to Library** and **Try again** are both on that screen. To remove a drive later, choose **Disconnect** in the same panel. + +Access is read-only. Cortex does not write back to a drive, and there is nothing to paste: you sign in to the drive, and that is the whole setup. + +## Attach a drive item to a chat + +The composer's attach menu lists, in this order, **Attach file**, **Image** and **Check origin**, then **From your Library** and a **CLOUD DRIVES** block. + +1. Open the attach menu and choose the drive under **CLOUD DRIVES**. +2. Browse or use **Search this drive**. +3. Pick the item. It attaches without a second upload, and the answer cites the original back to the drive it came from. + +Attached drive items also appear in Library with the **Connected drive** badge, so you can find one again from there. In its preview dialog, the action to open it on the drive takes you back to the original. + +## When drives are not available + +A deployment with no drives configured simply shows no **Connect** control, and there is nothing to do about that from the app. A guest always sees drives as unavailable, for the same reason a guest cannot hold a grant. If neither applies and a drive still will not connect, disconnect it and connect again; nothing in your Library is changed by a failed connection. + +## Related + +- [Library](/chat/library) - the file store, versions, storage and row actions +- [Attachments](/chat/attachments) - what happens to a file on a single turn +- [Projects](/chat/projects) - adding a file as a project source +- [Sharing and teams](/chat/sharing) - what else is per account today +- [Connectors](/chat/plugins) - connected apps, which are a different surface diff --git a/chat/library.mdx b/chat/library.mdx index 60a9991..5502eb8 100644 --- a/chat/library.mdx +++ b/chat/library.mdx @@ -1,59 +1,98 @@ --- title: "Library" -description: "Everything you uploaded to a chat or a project, and everything the assistant produced. Files stay in Library when a chat is deleted." -keywords: ["Artifacts", "files", "uploads", "attachments", "file store"] +description: "Every file your account holds: what you uploaded, what Chat produced, and what you attached from a connected drive." +icon: "box-archive" +keywords: ["Artifacts"] --- -Library is the file store on your account. Anything you attach in a chat, add to a project, or upload directly lands here, and so does everything the assistant generates — pictures from Cortex-Image-1 included. Open it from **Artifacts** in the sidebar. +**Library** is the file store on your Cortex account. Its own lead says what it collects: files you uploaded, generated, or attached from a connected drive. Sharing never moves ownership. Deleting a chat does not delete the files that passed through it; they stay in Library until you remove them there. - - Library — Nothing in your library yet. Attach a file in a chat, add one to a project, or upload it here. - +This page covers how files arrive, how to find one, what the row actions do, how versions and **Restore** work, how pinning and the storage allowance behave, and how a file gets back into a chat. Sharing a file and connecting a drive have their own page, [Sharing files and connected drives](/chat/library-sharing). -## How files get in +## How files arrive -| Route | What happens | -| --- | --- | -| **+ → Attach file** in the composer, or drop a file on it | The file is checked, stored in Library, and attached to the turn | -| Add a file to a project | The file is stored in Library and available to that project's chats | -| **Upload** in Library | The file is stored for later use | -| The assistant generates something | Generated files — images, documents — are saved here | +| Source | Badge | What it is | +| --- | --- | --- | +| An upload | **Uploaded** | The **Upload** button in Library, or an attachment on a chat turn. | +| Something Chat made | **Generated** | An image from Cortex-Image-1, a document or deck export, an exported research report, or files a sandbox run wrote out. | +| A project source | **Project** | A file added to a project so its chats can read it. | +| A drive item | **Connected drive** | An item attached from a drive you connected, without a second upload. | + +Notes are the fifth route in. Select text in an answer and Chat offers **Start writing** and **Save to Library**; a saved note is filed as a **Document**. Saving a note does not spend your per-upload allowance, and a guest may save one. A selection that crosses a code fence is ignored. + +Files a sandbox run writes are collected when the run finishes, at most 10 files and 10 MiB in total, and only the files directly in its output folder. While it works, the thread says **Collecting files from /outputs**, and the result is confirmed with **saved to Library**. If a run produced nothing to keep, the thread says so rather than leaving a gap. -Type and size checks run at upload. A rejected file is not attached and does not appear in Library. +Generated formats are filed by what they are. Generated HTML is filed as **HTML**, a generated CSV or TSV as **Sheet**, and an SVG or a `.js` file stays an **Upload**. -## Use a file in Chat +## Find a file -Pick from Library when you start a turn, or attach a fresh file. The conversation receives the file as an attachment. Cortex does not fetch a URL you paste as if it were an attachment — paste a link and Chat will read it as text, or use web tools to fetch the page. +- **Search files** matches by name; the other search box matches by name or conversation, so you can find a file by the chat it came from. +- The **Scope** pills switch between **Your files** and **Shared with me**. A file someone shared with you carries a **Shared by** line, and ownership stays with them. +- The **Type** filter narrows to **All**, **Images**, **PDFs**, **Code** or **Other**, and to artifact kinds including **Reports**, **Decks**, **Documents**, **Sheets** and **Research**. +- Each row also carries a kind badge: **Upload**, **Image**, **Deck**, **Document**, **Sheet**, **PDF**, **HTML** or **Report**. -Deleting a chat does not delete its files; they stay in Library until you remove them there. +If nothing matches, Library says **No files match** and suggests a different filter or search. Under **Reports**, an empty list explains where reports come from: exported Deep Research markdown lands here. See [Deep Research](/chat/deep-research) and [Document export](/chat/document-export). -## Filters +## Work with a file -**All**, **Images**, **PDFs**, **Code**, **Other**. Generated pictures show under Images. +Row actions are **Open**, **Download**, **Rename**, **Delete** and **Share**. **Open** uses the preview dialog. Not everything previews in a browser: when it cannot, the dialog says the file is not shown inline and tells you to download it and open it in an application you trust. For a drive item, the dialog offers to open it on the drive it came from instead. -## Failure states +## Versions and Restore -A Library fetch that fails shows an **error square** in the thread — never a spinner that spins forever. Retry the turn; if the file is gone from Library, attach it again. +Every Library file has a version history. Saving it creates version 1. -## Guests + + + From the file's actions, open **Versions**. The rail lists each **Version**, with the newest marked **Latest** and the live one marked as current. + + + Choose **Restore** on that version. + + + Library confirms with **Version restored** and tells you which version is now the latest. + + -Library needs a signed-in account. A guest can attach files to the current session; they are not kept once the session ends. See [Accounts](/getting-started/accounts). +Restoring never overwrites and never loses anything: the older contents are copied onto the live file and appended as a new latest version. Two restores at once are serialised, so the history stays consistent. A version whose underlying bytes have already been collected can no longer be restored, and Library says so rather than failing silently. -## Library across the products +## Pinned work -Chat's Library is the file store for your account, and it is a Chat surface — Code sessions work in their guest's filesystem, and a bot has its own computer. The one other thing called a library is the [Design library](/design/library): components, pages, and tokens for canvases, which lives in the Design desktop app and shares nothing with this one. +Pinning is shared between conversations and projects, with room for 20 pinned items across the account. A pinned item leaves **Recents** and appears in the pinned section instead. Once you have pinned anything, the pinned section stays visible even after you later empty it. -| Object | Product | What it holds | +## Storage + +The **STORAGE** meter counts every file on the account against your plan's allowance. It stays muted below 80 per cent of the allowance, turns to a warning at 80 per cent, and refuses new files once it is full. + +| Meter state | What you see | What it means | | --- | --- | --- | -| **Library** (this page) | Chat | Files you uploaded, and files the assistant produced | -| [Design library](/design/library) | Design | Components, pages, tokens | -| Code session files | Code | The repository checked out in that session's guest | -| Bot computer files | Bot | Files on that bot's own desktop | +| Empty | No Library storage used yet. | Nothing stored. | +| Normal | A muted bar, used of limit | Below 80 per cent. | +| Warning | Your Library is almost full. New files stop at this plan's limit. | 80 per cent or more. | +| Full | Your Library is full on this plan. Delete files to make space. | New files are refused. **Manage files** takes you to the list. | +| Error | Storage usage could not be loaded. Files stay where they are. | The read failed. Nothing was deleted; use **Retry**. | +| Unavailable | Library storage is unavailable on this plan. | This plan carries no allowance, so no bar is drawn. | + +The allowance itself depends on your plan. The meter prints its own limits line, `Guest 200 MB · Free 500 MB · Pro 20 GB. Deleting a file frees its storage.`, which names three plans rather than all five and whose labels do not line up with the plan names on the plan list: the 20 GB it shows against Pro is the **Plus** allowance, and the Pro plan carries no storage ceiling at all. [Plans](/getting-started/plans) carries the value for every plan. When a generated file cannot be kept because the allowance is full, Chat says **Storage limit reached** and tells you the file was not saved. + + +A single upload is capped at **10 MB max** in the web product, whatever your plan's wider allowance is. A larger file is refused before it is stored; see [payload_too_large](/problems/payload_too_large). Generated images and saved notes do not spend the per-upload allowance. + + +## Use a Library file in a chat + +In the composer, type `@` or choose **From your Library** in the attach menu to pick a file you already have. The picker searches your files and files shared with you, and they attach without a second upload. **Choose from Library** is the full picker; it tells you plainly that guests have no Library picker. + +Chat can also look a file up for you. It searches your own Library by name, newest first, and if a name does not resolve it names up to five candidates back to you rather than guessing. What it reads is handled as untrusted material, exactly like a project source. + + +Library needs a signed-in account. A guest is told to sign in to upload, save notes, download or delete files, and cannot share a Library file at all. See [Accounts](/getting-started/accounts). + ## Related -- [Projects](/chat/projects) — pin files to a body of work. -- [Image generation](/chat/images) — generated pictures land here. -- [Origin check](/chat/origin-check) — check attached media. -- [Design library](/design/library) — a different object: components, pages, and tokens for canvases. -- [Settings → Data & privacy](/getting-started/settings) — export or delete everything. +- [Sharing files and connected drives](/chat/library-sharing) - grants, copy link, and drives +- [Projects](/chat/projects) - files added as project sources +- [Attachments](/chat/attachments) - putting a file on a single turn +- [Image generation](/chat/image-generation) - where generated pictures land +- [Design library](/design/library) - a different object: components, pages and tokens +- [Limits](/reference/limits) - allowances by plan diff --git a/chat/mcp-servers.mdx b/chat/mcp-servers.mdx new file mode 100644 index 0000000..cc4e914 --- /dev/null +++ b/chat/mcp-servers.mdx @@ -0,0 +1,115 @@ +--- +title: "MCP servers" +description: "Attach a Model Context Protocol server over HTTP, sign in when the server asks, see how its tools appear in a chat, and remove it again" +icon: "server" +--- + +An MCP server is a server you run, or subscribe to, that offers tools over HTTP. Attaching one adds its tools to your chats, so the model can call them in the middle of a turn the same way it calls anything else. Cortex describes the section in those terms: **Attach a Model Context Protocol server over HTTP; its tools join the model in chat.** + +This page covers where the add form lives, what Cortex checks before it stores anything, what happens when a server asks you to sign in, how the tools show up in a turn, how to let bots use them, the caps, and what to expect when a server stops answering. + +## Where to add a server + +Open **Settings** and go to **Integrations**. Two sections sit there: + +- **Apps**, described as **Connect an app to act on it from chat. A connected integration adds its tools to your conversations.** These are the catalogue connectors. See [Connectors](/chat/plugins). +- **MCP servers**, which is the one you want here. + + +The Connectors page has no MCP form. If you went looking for it there, come back to **Settings** and **Integrations**. + + +## Add a server + + + + **MCP server name** is a short label of your choosing. It becomes the prefix on the server's tool names, so keep it recognisable. + + + **MCP server URL** takes the server's address. It is an `https` address ending in the server's MCP path. There is nothing to configure beyond the name and the URL. + + + **MCP server bearer token** is optional, and it is a password field. Leave it empty unless you already hold a credential for the server. + + + The button reads **Add**, then **Adding…** while it works. Cortex checks the server is reachable and asks it for its tool list before it stores anything. + + + +The finished row shows the name, the URL truncated, **authenticated** when a token is held, and a **Remove** button. + +## Sign in when the server asks + +Some servers require authorisation. When one says so, Cortex takes you to that server's own sign-in page and finishes the connection when you come back. You have a few minutes to complete it. + +Nothing is stored until you return. If you cancel, nothing was created. + +The return screen reads **Connecting your server** with **Cortex is finishing the connection. This takes a moment.**, then **Finishing the connection…**, then confirms with the server's name and **is connected. Taking you back…**. When it does not work you get one of two honest endings, both of which change nothing: + +- **The server was not connected**, with **Nothing was changed. You can start again from Connectors.** +- **The connection did not finish**, with **Cortex could not finish the connection. Nothing was changed.** + +Either way, **Back to Connectors** returns you to the product. + +## The bearer token is a different thing + +Signing in and pasting a token are not two routes to the same place. The token field is for a server you run yourself, where you already hold a credential and no sign-in dance is needed. It reaches nothing except the endpoint you typed. + +## How the tools appear in a turn + +Each attached server's card lists the tool names the server advertised. In a chat, those tools are named after your server and the tool, so it is clear where a call went. Their results are treated as third-party content, the same as any other outside source, which means text arriving from a server cannot act as an instruction to the model. See [Built-in tools](/chat/tools) for how Cortex handles any tool result. + + +The tool chips are a snapshot taken when the server was attached, not a live read. A server that has gained a tool since then will not show it, and will not offer it, until you attach it again. If the card says **No tools were advertised when this server was attached.**, that server offered nothing at that moment. + + +## Let bots use a server + +Each card carries a **Cortex Bot** switch, described as **Let your mascots use these tools. Off by default; each call still asks first.** A server you attached to give Chat a tool does not silently become a bot's tool too: you turn it on per server, and each call is still confirmed. + +The switch is not available while the server itself is not enabled, or while a change is still being saved. + +## Caps + +| Limit | Value | +| --- | --- | +| Servers per account | 4 | +| Tools per server | 24 | +| Transport | Streamable HTTP only | +| Availability to Cortex Bot | Off by default, per server | +| Guests | Cannot attach a server | + +A guest cannot attach an MCP server, and the refusal happens before Cortex makes any outbound request at all. + +## When a server stops answering + +If a server's sign-in has expired, Cortex marks it as needing reconnection and skips it for that turn rather than failing the whole answer. A brief network problem is skipped the same way, and nothing about the server is changed. Reconnect it when you next notice the mark. + +## Remove a server + +**Remove** on the row detaches the server and its tools. There is no separate edit form: to change a URL or a token, or to pick up tools the server has added since, remove it and add it again. + +## Who is allowed to change this + +A **Roles** block explains which of these controls you can use: **Your role decides which of these controls you can use.** The relevant grant is **Manage connectors**, described as **Connect, configure and disconnect the account's apps and MCP servers.**, and it shows as **Granted** or **Not granted**. Refusals are specific: **Sign in to connect an app.**, **Your role cannot change this connector.**, or the same sentence naming your role. + +Where the deployment says nothing about roles, the block says so rather than guessing: **This deployment does not report roles, so nothing here is inferred.** Custom roles, when your organization uses them, are managed by your organization. + +## Organization servers + +An **Organization** block lists **Servers the organization provisioned. Members cannot add past a lock. Secrets never appear here.** Each entry can carry a policy of **Lock**, **Require** or **Deny**, and the surfaces it names are **Chat**, **Code** and **Bot**. Only an organization admin can change policy. + + +This block is informational today. Servers listed there do not add tools to your chats, so do not count on one for a turn. Where a deployment has none, it says **No organization servers on this deployment.** A guest sees **Organization servers are available after you sign in.** + + +Also on the same tab are rows for first-party connectors, which show **Connected**, their tool count, **Disconnect**, or a **Coming soon** badge where the connector is not ready. + +## Related + +- [Connectors](/chat/plugins) +- [Built-in tools](/chat/tools) +- [Page tools](/chat/page-tools) +- [Skills in Chat](/chat/skills) +- [Settings](/getting-started/settings) +- [MCP in Cortex CLI](/cli/mcp) diff --git a/chat/memory.mdx b/chat/memory.mdx index 253652f..b3b71af 100644 --- a/chat/memory.mdx +++ b/chat/memory.mdx @@ -1,49 +1,105 @@ --- title: "Memory" -description: "Cortex remembers preferences and facts you share so answers get more personal over time. Review or delete individual memories under Settings → Data & privacy." -keywords: ["preferences", "personalisation", "saved facts", "forget"] +description: "What Cortex remembers, how to review, edit, delete, export and import it, and how to scope memory to a single project." +icon: "lightbulb" --- -Memory is a short list of standing preferences and facts about you that Chat keeps on your account and reads into every conversation. It is how Cortex remembers that you prefer British spelling, work in euros, or want answers to start with the conclusion — without you repeating it. +**Memory** is a short, readable list of standing facts and preferences you have told Cortex Chat. It is the mechanism that stops you repeating that you work in euros, prefer British spelling, or want the conclusion first. The setting describes itself the same way: Cortex remembers preferences and facts you share so answers get more personal over time, and you can review or delete individual memories. - - Memory, two-factor authentication, and Your data controls under Settings → Data & privacy - +Memory is on by default, and everything about it is inspectable. This page covers where to manage it, what it stores, how long it is kept, how to review and delete entries, how to narrow memory to one project, how export and import work, and the cases where memory deliberately does nothing. -## What memory is +## Where to manage memory -| Memory is | Memory is not | -| --- | --- | -| Account-wide — it follows you into every chat | A [project](/chat/projects) — project instructions apply to one body of work | -| Short — preferences and facts, not documents | A file store — that is [Library](/chat/library) | -| Explicit to forget — deleting a memory is a delete | A hidden profile you cannot see | +Everything below lives in **Settings → Data & privacy**, under **Memory**. The same panel carries the master switch, the sensitive-topics switch, the retention row, the searchable list of entries, and the export and import controls. The project-scope choice is the one part that lives elsewhere: it is inside each project, under its own **Memory** block. See [Projects](/chat/projects) and [Data and privacy](/getting-started/data-and-privacy). + +## What memory stores + +Memory holds what you told Chat, not your documents. Entries are grouped for review under **Facts**, **Context**, **Preferences**, **Instructions** and **Other**, and each one carries where it came from, shown as **Saved from Chat**. Files belong in [Library](/chat/library), and a body of work belongs in a project. Your instructions and your memories are stored encrypted. + +## Turn memory on or off, and narrow what it saves + +- **Use memory** is the master switch. When it is off, Cortex neither recalls nor writes new memories, and existing ones stay until you delete them. +- **Include sensitive topics** is off by default. With it off, Cortex skips health, finances and similar topics when saving memories. It declines at the moment of writing rather than saving something and filtering it later. This switch can only be changed while **Use memory** is on. + +Turning memory off stops the live part only. Listing, editing, deleting, importing and exporting all keep working with the switch off. What stops is recall during a turn and the writing of anything new. + +## How long memories are kept -## How memories are created +The **How long to keep memories** row sets the retention window. It applies to new and existing memories on the account, and project memories follow the same window. The pills offered are **30 days**, **90 days** and **Keep until deleted**. -Chat saves a memory when you tell it something worth keeping — *always answer in French*, *my team ships on Thursdays* — or when it recognises a standing preference from how you work. Memories are read at the start of a turn alongside project instructions. +If no window is shown, that is deliberate. A number here is a promise about deletion, so the product shows the value your plan actually carries rather than inventing a default. -## Review and forget +## Review, edit and delete - - Scroll to **Memory**. Every saved memory is listed. + + Go to **Settings → Data & privacy** and find **Memory**. - - Each entry is a short sentence in plain language. + + Use **Search memories**, or read down the topic headings. If nothing matches, the panel says **No memories match that search.** - - Deletion is immediate and per memory. There is no buried toggle. + + Choose **Edit** on a row, change the text, and choose **Save**. Editing re-files the entry: its wording changes, its grouping is recalculated, and it is marked as having been edited by you. + + + Choose **Delete** on the row. Deletion is per entry and immediate. + + + Use **Load more** for older entries. -Memory needs a signed-in account. Guests see *Nothing saved yet*. +To clear a whole scope at once, use **Erase account memories** or **Erase project memories**. The fuller panel also offers a **Project** picker, so you can read one project's memories on their own. + +If you have never given Chat anything to keep, the panel says so: nothing is saved yet, Cortex stores standing preferences and facts you share, and you can delete any of them here. + +## Account memory and project-only memory + +Memory is account-wide by default, so it follows you into every chat. A project can be switched to read a narrower set. Inside the project, the **Memory** block offers: + +| Choice | What chats in that project read | +| --- | --- | +| **Account memory** | Memories saved across your account. | +| **Project only** | Only memories saved in that project. Account memories stay where they are. | + +Switching the scope never deletes anything. It changes what is read on a turn. One consequence worth knowing: an import started from the account panel always writes account memories, whatever a project is set to. + +## Export and import + +**Export memories** saves a plain-text file called `cortex-memory.txt`, one memory per line. Keep it as a backup, read it to audit what Cortex holds, or edit it and bring it back. + +**Import memories** takes those lines back in. Paste them into the import box and choose **Import memories**. The rules are strict on purpose: + +- Import only adds. It never overwrites and it never deletes. +- One memory per non-empty line, and at most 200 lines in a single paste. A longer paste is refused before anything is processed. +- If any line fails, the whole import is rolled back, so a partial import cannot leave you with half a list. + +## Temporary chats + + +A **Temporary chat** never reads or writes memory. It is also kept out of **Recents** and is deleted after 30 days. The composer says exactly that when you turn one on. Use it for a question you do not want shaping later answers. + + +## Searching past chats + +Recall from memory is not the same thing as reading your old conversations. Searching past chats is a separate capability behind its own explicit consent, and the default is no. When it is granted, the model can find titles and snippets from your conversations, capped at ten results, and it never includes temporary or archived conversations. + + +There is no control in the product for granting that consent yet, so searching past chats is not something you can switch on from Settings today. Memory itself, on this page, is fully available. + + +## When memory cannot be read -## Plans +If the memory setting itself cannot be read, the turn is treated as memory off and the panel tells you: memory could not be loaded, so it stays off, and nothing is listed or saved until the setting can be read. It fails closed on purpose, so an outage never turns into a silent write. -Go and Plus list **extended memory and context** among their features. See [Plans](/getting-started/plans). + +Memory is stored on your account, so a guest session has none. The panel asks you to sign in to review it or turn it off. See [Accounts](/getting-started/accounts). + ## Related -- [Projects](/chat/projects) — instructions scoped to one body of work. -- [Security](/security/overview) — what Cortex stores and how to export or delete everything. -- [How Chat works](/chat/how-it-works) — where memory enters the prompt. +- [Projects](/chat/projects) - standing instructions, and project-only memory +- [Data and privacy](/getting-started/data-and-privacy) - the settings tab memory lives on +- [Conversations](/chat/conversations) - temporary chats, pinning and recents +- [How Chat works](/chat/how-it-works) - where memory enters a turn +- [Built-in tools](/chat/tools) - the tools a turn can reach for diff --git a/chat/models.mdx b/chat/models.mdx index e41b4d5..4f7a13e 100644 --- a/chat/models.mdx +++ b/chat/models.mdx @@ -1,57 +1,100 @@ --- title: "Models and thinking" -description: "Pick a model per conversation from the composer chip, set how long Cortex thinks before answering, and know what happens at peak hours." -keywords: ["Cortex 1 Mini", "Cortex Teutonic-1", "thinking level", "model picker", "context window"] +description: "The two models Cortex Chat offers, what the Preview badge means, why the model is fixed per conversation, and the three thinking levels" +icon: "microchip" --- -Every conversation runs on a Cortex model. The chip under the composer — *Cortex 1 Mini · Preview · Thinking Low* by default — is where you change it. The choice belongs to the conversation: existing threads keep the model they were created with, and new chats start from the default. +Every conversation in Cortex Chat runs on one model, and the chip under the composer is where you see and change it. The chip is plain text with a chevron: it shows the display name of the model in use, never the word "Model" in front of it, and it can carry a short detail after the name, such as the thinking level currently set. - - Model picker — Cortex 1 Mini and Cortex Teutonic-1 in Preview, Thinking Low / Medium / High, and Deep Research - +This page covers the two models Chat publishes today, what the **PREVIEW** badge on them means, how the model and the thinking level are decided, and what Chat tells you when a model is busy or cannot be reached. -## What you can pick +## The two models -| Model | Status | Context | Capabilities | Role | -| --- | --- | --- | --- | --- | -| **Cortex 1 Mini** | Preview | 262.1K | Reasoning, tools | The model Cortex is serving today. Default for new chats. | -| **Cortex Teutonic-1** | Preview | 32.8K | Reasoning, tools | Second public preview, under active training. | -| **Cortex-Image-1** | Preview | — | Image generation | Used when you ask for a picture. Built on NVIDIA Cosmos. See [Image generation](/chat/images). | +The list in the panel is fetched from Cortex when the page loads rather than built into the app, so it always reflects what your account can actually use. Today it holds two entries, and both are marked Preview. -The composer model chip is a Chat control. Web Code has no model picker; the CLI has its own `/model` picker with the same family under English names (**Cortex Mini 1**, **Cortex 1**, **Cortex Max 1**) — see [CLI modes](/cli/modes-and-permissions). +| Model | Description in the panel | Context window | Thinking | +| --- | --- | --- | --- | +| **Cortex 1 Mini** | *Preview — the model Cortex is serving today.* | 262,144 tokens | Yes | +| **Cortex Teutonic-1** | *Preview (under active training).* | 32,768 tokens | Yes | - - Settings → Models — Cortex 1 Mini, Cortex Teutonic-1, Cortex-Image-1, default thinking level, reasoning summaries - +Cortex 1 Mini is the model Chat serves by default. Cortex Teutonic-1 is a second preview with a smaller context window. -## Thinking level +Each model also caps how long a single answer can be. Cortex 1 Mini writes up to 32,768 tokens in one answer. Cortex Teutonic-1's ceiling is lower, and because it is still under active training you should not plan a long single-shot generation around it: split the work into turns instead. -**Low**, **Medium**, or **High**. Higher thinking spends more time before answering and suits multi-step reasoning, careful writing, and anything where a wrong first draft is expensive. Low is right for quick questions. The level is per conversation; a saved default under **Settings → Models** is marked *coming soon*. +Neither of these models advertises image understanding, which matters when you attach a picture. See [Attachments and files](/chat/attachments). -**Show reasoning summaries** (also *coming soon* in Settings) displays a short summary of the model's thinking above each answer. +Image generation does not use either of them. Asking Chat for a picture routes to a separate image model that is not offered in this picker, as described in [Image generation](/chat/image-generation). -## Deep Research +## What Preview means -The toggle at the bottom of the chip turns a conversation into a research run: plan the questions, read live sources, and write a cited report. It is a Chat feature only. See [Deep Research](/chat/deep-research). +Both rows carry an uppercase **PREVIEW** badge. It is a maturity signal about the name, not a different service: a preview model is served on the same production path as anything else. Read it as "this model is new and may change", not as "this model is running somewhere experimental". -## How a turn uses the model + +Because both published models are previews, every row in the picker shows the badge. Nothing is hidden behind it, and there is nothing to opt into. + -1. You pick the model on the conversation. -2. Chat assembles the prompt — your message, attachments from Library, memory, project instructions, tool results — and clamps generation so prompt plus output fit the model's context window. -3. The model runs the tool loop until it stops or reaches Chat's round budget. See [How Chat works](/chat/how-it-works). +## The model belongs to the conversation -Completions for Teutonic use their own upstream. If that upstream is not configured on a deployment, the request fails closed before any quota is spent and never falls through to Mini. +The model is chosen when a chat starts and stays fixed for the life of that conversation. There is no control that swaps the model of an existing thread. If you want a different one, start a new chat. -## Availability and peak hours +A model your plan cannot reach is listed in the panel with the reason, rather than being hidden, on the principle that knowing what a plan would add is useful information. In practice no Chat model is plan-gated today: both are available from the Free plan up, so you will not meet a locked row in Chat. -Model availability depends on your plan. During peak hours new chats may fall back to a faster model; the chip always tells you which model is serving the conversation. Go and higher plans get priority when the fleet is busy — see [Plans](/getting-started/plans). +**Set as default…** is in the panel but not wired yet. Choosing it answers **Set as default is not available yet — the session default is chosen when the chat starts.** -## What this page is not +## Use a different model for one message -There is no public inference API on this site. Model names here are product names inside Cortex Chat, not endpoints. See [Coming soon](/platform). +The one exception to the fixed model is a single message. + + + + Click the chip under the composer. + + + Pick **This message only**, then pick the model. The hint states the scope: **Applies to your next message. The session default is unchanged.** + + + The chip shows the chosen model followed by *this message*, so you can see that the override is armed. It applies to the next message you send and then falls away. + + + **Reset to** the session default puts the chip back. The session default itself is shown as the model name followed by *session default*. + + + +## Thinking effort + +Thinking is a three-way choice under the **THINKING** heading in the model panel: **Low**, **Medium** or **High**. The panel states what you are trading: **Higher thinking spends more time before answering.** Arrow keys move between the three levels and wrap around. + +Use Low for quick factual questions where a fast answer is the point. Use High for multi-step reasoning, careful writing, and anything where a wrong first draft is expensive. Medium is a reasonable middle for everyday work. + +Two things are worth knowing about the control itself: + +- It is attached to the model, not to your plan. Thinking runs are not metered on any plan, so raising the level costs you nothing beyond the wait. +- It is drawn only on a model that supports thinking, and simply absent on one that does not, rather than greyed out. Both models published today support it, so you should always see it in Chat. + +## What you see while a model thinks + +While the turn runs, the reasoning streams into a collapsible **Thinking** block. Before the first tokens arrive it reads **Waiting for the first tokens…**. When the answer starts it collapses to a single line, **Thought for** a duration, or **Thought about this** when the duration was not recorded. + +Some turns do no thinking at all. The block then says **No reasoning was recorded for this turn.**, which is a normal outcome and not a failure. + +## When a model is busy or unavailable + +Chat never quietly substitutes one model for another. If something is wrong you are told, and you are offered whatever is still available. + +| What you see | What it means | +| --- | --- | +| **Loading the available models.** | The model list has not arrived yet. Sending waits for it | +| A reason followed by *Sending is unavailable until the model list loads.* | The list could not be fetched. Nothing is sent in the meantime | +| **No models are available on your account.** | Your account currently has no usable model. Check your plan | +| **You’ve reached today’s limit for this model** | The daily allowance for that model is spent, with a line telling you when it resets | +| **You’ve reached this month’s limit for this model** | Same, for the monthly allowance | + +When a per-model limit is reached, the banner names the model that is still available and offers a button to use it. That is a choice you make, not a switch made for you. ## Related -- [Streaming](/chat/streaming) — tokens as they arrive. -- [Settings](/getting-started/settings) — defaults for new chats. -- [Plans and quotas](/getting-started/plans) — quotas fail closed. +- [Streaming and reconnects](/chat/streaming) - how an answer arrives once a model starts writing. +- [How Chat works](/chat/how-it-works) - what goes into a turn and how the context window is used. +- [Attachments and files](/chat/attachments) - what happens to a file you send a model. +- [All models](/reference/models) - the reference list across the products. +- [Plans and quotas](/getting-started/plans) - message allowances and what resets when. diff --git a/chat/origin-check.mdx b/chat/origin-check.mdx index caaca33..d7c86e4 100644 --- a/chat/origin-check.mdx +++ b/chat/origin-check.mdx @@ -1,46 +1,84 @@ --- title: "Origin check" -description: "Attach media and ask whether it is authentic. Cortex waits for a verdict, and says so plainly when the check cannot run." -keywords: ["authenticity", "AI detection", "verify media"] +description: "Attach a photo or a clip and ask whether it is authentic. Cortex answers with one of three verdicts, or says plainly that the check could not run." +icon: "fingerprint" --- -**Check origin** answers one question about a picture or a video you attach: does it look authentic, or does it carry the marks of generation or manipulation? It is an explicit ask on attached media — not something that runs silently on every image in a thread. +**Check origin** answers one question about a photo or a clip you attach: does it read as something a camera took, or as something that was generated? It is always an explicit ask on media you attach in **Cortex Chat**. Nothing is checked silently, and a picture Cortex generated for you is not labelled automatically. + +This page covers running a check, reading the verdict and the figures beside it, what Content Credentials add, the file sizes and formats the check accepts, and the difference between a check that failed and one that could not run at all. ## Run a check - - Choose **+ → Check origin** on the composer, or attach the file with **Attach file**. iPhone HEIC/HEIF photos are accepted. + + In the composer's attach menu choose **Check origin** and pick the file. Attaching the file the ordinary way and asking whether it is real, AI-generated or a deepfake works just as well. - - *Is this photo authentic?* or *Was this generated?* The turn runs the origin check on the attachment. + + The card shows `Checking origin…`. Cortex holds the rest of its reply until the verdict resolves, so you never get a confident paragraph followed by a result that contradicts it. - - Cortex holds its reply until a verdict paints. You will not get a confident paragraph followed by a result that contradicts it. + + The finished card carries the verdict, the figures behind it, whether the file arrived with Content Credentials, and a credit for the service that performed the check. -## When the check cannot run +## Reading the verdict -If origin check is unavailable on a deployment, the product says so instead of guessing. That is fail-closed behaviour, not a broken button: no verdict is still no verdict. Ask again later rather than reading silence as a result. +There are exactly three verdicts, and the middle ground is one of them rather than a rounded guess. -## What it is not +| Verdict | What it means | +| --- | --- | +| `Likely a camera photo` | The detector did not call it AI, and its confidence sits below 0.40. | +| `Likely AI-generated` | The detector called it AI, with confidence above 0.70. | +| `Couldn't tell with confidence` | Everything else. The file was analysed, and the result is not strong enough to claim either way. | -| It is | It is not | +Under the verdict, the card prints the AI likelihood as a percentage and a similarity figure, as `AI likelihood {percent}% · Similarity {similarity}`. + +The card also reports whether the file carried **Content Credentials**, the provenance information some cameras and editing tools attach to a file. Where there are none, it says `No Content Credentials attached.`, which is not itself a verdict: plenty of genuine photos carry no credentials. Credentials are read from the original file you attached, before Cortex compresses it for the check. + + +A verdict is about the file, not about the world. `Likely a camera photo` says the image looks camera-made; it does not vouch for what the picture claims to show, where it was taken, or when. + + +## What the check accepts + +| Item | Limit | | --- | --- | -| A check on media **you attach** | An automatic label on every generated picture | -| A Chat turn | A Code tool or a Bot skill | -| A verdict about the file's origin | A statement about the truth of what the picture shows | +| Maximum file size | 10 MB per file, the same ceiling that applies to any upload in Chat, whatever your plan. | +| Photos | The usual image formats Chat accepts, plus HEIC and HEIF. | +| Clips | Short video within the same 10 MB ceiling. | +| Allowance | There is no origin-check allowance. A check spends neither your image allowance nor your web-search allowance. | + +iPhone HEIC and HEIF photos are a deliberate exception: the ordinary image picker in Chat does not take them, but **Check origin** does. If you meet the hint `HEIC photos can be checked for origin. Use Check origin, or convert to JPEG or PNG.`, that is the product telling you which path to use. -Pictures generated with [Cortex-Image-1](/chat/images) are ordinary Library files. If you want to know whether one of them reads as generated, attach it and ask — the check does not run on its own after generation. +A file larger than the ceiling is refused when it is attached, so there is never anything for the check to read. See [`payload_too_large`](/problems/payload_too_large) and [Attachments and files](/chat/attachments). -## Sizes and formats +## When the check cannot run + +The wording on the card tells you which of three different things happened, and all three mean no verdict rather than a weak one. + +| Card | What it means | What to do | +| --- | --- | --- | +| `The origin check couldn't run.` with `Your image wasn't analyzed.` | The check was attempted and the file was rejected, for example because it was too large for the detector. A code and request id are printed beside it. | Use **Retry**, which re-sends the same file, or try a smaller or differently encoded copy. | +| `Origin detection is temporarily unavailable.` | Origin detection is not set up on this deployment. Nothing was analysed. | Ask again later. There is nothing to fix on your side. | +| `The origin check didn't finish.` | The request did not complete, typically a network problem between you and Cortex. | Retry the turn. | + +Cortex fails closed here on purpose. No verdict is still no verdict, and silence is never to be read as a result. + +## What origin check is not + +| It is | It is not | +| --- | --- | +| A check on media **you** attach and ask about. | An automatic label on every generated picture. | +| A Cortex Chat turn. | A Cortex Code tool or a Cortex Bot skill. | +| A judgement about how the file was made. | A judgement about whether the scene in it is true. | -An origin check runs on an attachment, so the same upload limits apply as anywhere else in Chat and [Library](/chat/library). A file that was rejected at upload is never attached, so there is nothing for the check to read — attach a supported file or a smaller one. See [`payload_too_large`](/problems/payload_too_large) for the ceilings and [Library](/chat/library) for the failure states. +Pictures made with [image generation](/chat/image-generation) are ordinary Library files. To know whether one of them reads as generated, attach it and ask, the same as any other file. ## Related -- [Library](/chat/library) — where attached and generated media live. -- [Image generation](/chat/images) — Cortex-Image-1. -- [Chat troubleshooting](/chat/troubleshooting) — what a check that cannot run means. -- [Security](/security/overview) — how Cortex handles your files. +- [Image generation](/chat/image-generation) creates pictures; origin check is the separate question. +- [Attachments and files](/chat/attachments) covers what a turn accepts and the size ceiling. +- [Library](/chat/library) is where attached and generated media are kept. +- [Built-in tools](/chat/tools) lists the tools a Chat turn can call. +- [Chat troubleshooting](/chat/troubleshooting) covers turns that end without a result. diff --git a/chat/page-tools.mdx b/chat/page-tools.mdx new file mode 100644 index 0000000..d2a001e --- /dev/null +++ b/chat/page-tools.mdx @@ -0,0 +1,103 @@ +--- +title: "Page tools" +description: "Tools a web page offers to Cortex: how they are discovered, and the consent card where you deny, allow once, or always allow each one" +icon: "globe" +--- + +Some web pages offer tools to an assistant: search this catalogue, add this to the cart, file this form. Cortex reads what a page declares about itself and then asks you before any of it is used. Nothing a page offers is available to the model until you have said yes to it. + +This page covers where the consent card appears, what Cortex does and does not read from a page, what each of the three answers means, how narrowly **Always** is remembered, why a card sometimes comes back, and what happens when a call is refused. + +## Where the card appears + +The same control serves two products. In Cortex Chat it appears as a card beside the execution consent in the conversation. In Cortex Bot it appears as an overlay on the bot's computer rail. See [The computer](/bot/computer). + +You will see the eyebrow **Page tools**, the page's own address in a monospaced line above the card, and, while something is waiting on you, a green dot with **Page tools · waiting for you**. The offer line names the page's origin and how many tools it wants to offer. + +## What Cortex reads from a page + +Only what is in the page's own HTML. If a page declares its tools in code that has to run first, Cortex does not see them, and the page simply offers nothing. That is deliberate: the detection is static and fails closed rather than executing a page to find out what it wants. + +An annotation Cortex does not recognise is treated as a **write**, never as a read. A page cannot get a quieter prompt by labelling something in a way Cortex has not seen before. + +In Chat, Cortex fetches the page from its own side. It does not use your browser and it does not carry your cookies to that page, so a page tool never acts as your signed-in self by accident. + +## Decide on a tool + + + + The card names the site that is asking and how many tools it has declared, with the page's address printed above. + + + Every tool carries **Read** or **Write**. A read row says **This tool can read the current page.** A write row says **This tool can change the current page. Review it before allowing.**, and it is tinted and bordered with the warning colour so it does not read like the rest. + + + **Deny** refuses it. **Allow once** permits this call and nothing more. **Always** is the standing grant, and it is the emphasised button. + + + +## What Always actually remembers + +**Always** is much narrower than it sounds. It remembers a combination of four things: + +| Part of the grant | Meaning | +| --- | --- | +| The site | The page's origin, not the whole web. | +| The tool name | That tool, not its neighbours. | +| The shape of the arguments | The arguments the site declared, as it declared them. | +| Read or write | A read grant is not a write grant. | + +Change any one of those and the grant no longer matches. In particular, an **Always** for a read-only version of a tool does not carry over once that same tool starts writing: you get asked again. + +**Allow once** expires. **Always** does not. + + +Cortex does not publish a screen for reviewing or withdrawing decisions you have already made, so treat **Always** as a standing grant for that exact combination. + + +## When a card comes back + +If a site changes what it declares, the decision you made no longer describes what is being asked for, and the card returns with **These tools changed. Allow them again.** Read the rows again before you answer, because a tool that used to read may now write. + +## Nothing you have not granted reaches the model + +Denied tools, tools still waiting on you, and everything on a guest session are simply absent from the list of tools the model can see. The model is not told about a page tool it cannot use, so it cannot try to use one and cannot tell you about one you refused. + +## Signing in + +Allowing a page tool needs an account. A guest sees a single **Sign in** button in place of **Allow once** and **Always**, with the hint **Sign in to allow page tools. You can still deny them.** + +**Deny** still works for a guest. Refusing something never requires an account. + +## When you see nothing at all + +Most pages are ordinary pages, and an ordinary page renders no card and no chip. The card only ever shows rows that are waiting on you or that have changed. Once every row has been decided, the whole card disappears rather than sitting there listing settled decisions. + +The card re-checks the page every four seconds, so a page that declares its tools a moment after it loads still reaches you. + +## When a call is refused + +Arguments are checked before every call, including calls covered by an **Always** grant. A missing argument, one of the wrong type, one outside the range the site declared, or one the site never declared at all, is refused rather than sent. + +The refusal names which argument was wrong. It never repeats the value, so nothing you typed is echoed back into the conversation. + +## Limits + +| Limit | Value | +| --- | --- | +| Discovery | The page's static HTML only | +| An unrecognised kind annotation | Treated as a write | +| What **Always** keys on | Site, tool name, argument shape, read or write | +| **Allow once** | Expires | +| **Always** | Does not expire | +| Guests | **Deny** works; **Allow once** and **Always** are refused | +| Re-check interval | Four seconds | + +## Related + +- [Connectors](/chat/plugins) +- [MCP servers](/chat/mcp-servers) +- [Built-in tools](/chat/tools) +- [The computer](/bot/computer) +- [Approvals in Cortex Bot](/bot/approvals) +- [Chat troubleshooting](/chat/troubleshooting) diff --git a/chat/plans.mdx b/chat/plans.mdx index 8150301..2798124 100644 --- a/chat/plans.mdx +++ b/chat/plans.mdx @@ -1,57 +1,110 @@ --- -title: "Plans" -description: "A plan is a task list the model can build and keep up to date while you work. Start one from any chat, or from Planning." -keywords: ["Planning", "task list", "checklist", "steps"] +title: "Planning" +description: "The task-list surface in Cortex Chat: start a plan from the Planning page or from a chat, then tick steps off as the work moves." +icon: "list-check" +keywords: ["Plans", "task plans"] --- -A plan turns a long answer into steps you can tick off. Start one from a thread with **Start a plan**, or from the **Planning** page with **New plan**. Plans are kept up to date as the work moves, and a plan started from a chat outlives that chat if you delete it. +**Planning** is the task-list surface inside Cortex Chat. A plan is a list of steps that you or the model can keep up to date while the work moves: you open it on the **Planning** page, tick steps off, and add new ones as they appear. This page is about that surface only. It is not about subscriptions, allowances or billing, so if you arrived looking for what your account includes and what it costs, read [Plans and quotas](/getting-started/plans) instead and come back here when you want task lists. - - Planning — No plans yet. A plan turns a long answer into steps you can tick off. - +This page covers what a plan is and what it deliberately is not, the two ways a plan gets created, how steps and statuses behave, the status filter, and the messages you see when an action fails. -## Start a plan from a chat +## What a plan is -Open the thread and choose **Start a plan** in the header. The title is prefilled from the conversation; add steps if you already know them — one per line, and a pasted numbered list works as is. +The Planning page states it in one line: `A plan is a task list the model can build and keep up to date while you work. Start one here, or ask for one in any chat.` - - Start a plan from this chat dialog with Title and optional Steps - +A plan is **not a calendar**. It carries no dates, because what it tracks is what is left to do, not when it happens. Two nearby things are often mistaken for it: -## Start a plan from Planning +| You want | Use | +| --- | --- | +| Something to run at a time, on a cadence | [Scheduled tasks](/chat/scheduled-tasks) | +| The set of questions a research run will answer | the research plan in [Deep Research](/chat/deep-research), which is a brief, not a task list | +| Standing instructions and files that apply to many chats | [Projects](/chat/projects) | + +## Start a plan + + + + + + The dialog explains itself: `A title, and one step per line. Bullets and numbers are stripped, so a list can be pasted straight in.` + + + Up to 200 characters. The placeholder shows the shape it expects, for example `Ship the pricing page`. + + + One step per line. Pasting a bulleted or numbered list works as is, because the bullets and the numbers are stripped for you. + + + The plan opens. If it cannot be saved you see `The plan could not be created`. + + + + + + + The conversation hands its work to a new plan. + + + A plan that came from a conversation is marked **From a chat** and carries a link, **Open the chat this came from**, so you can always get back to the thread that produced it. + + + You do not have to use the menu. Ask a chat to plan the work and the plan appears on the Planning page. + + + + + +Open the Planning page from the product navigation. + +## Work through the steps + +Open a plan from the list. **All plans** takes you back. + +- **Tick a step** to move it from `To do` to `Done`. Ticking it again moves it back. Clicking only ever cycles between those two. +- **Add a step** with the field at the bottom, up to 500 characters, then **Add**. +- The progress bar reads how many of the plan's steps are done. +- **Delete plan** removes the plan. It does not touch the conversation it came from. + +An empty plan says so, and tells you the second way to fill it: `No steps yet. Add the first one below, or ask in a chat and the model will fill it in.` + +## Statuses + +A plan has a status, but you rarely set it. The status is derived from the steps, and ticking the last box closes the plan on its own. The **Plan status** control is there when you want to override it. + +| Plan status | Meaning | +| --- | --- | +| `Draft` | Created, nothing worked yet | +| `In progress` | Some steps are done, some are not | +| `Done` | Every step is accounted for | -Choose **New plan**. Give it a title and, optionally, steps. Bullets and numbers are stripped, so a list can be pasted straight in. +| Step status | Who sets it | +| --- | --- | +| `To do` | you, or the model | +| `Doing` | the model, while it is working on that step. This is the only step status that draws a badge | +| `Done` | you, by ticking; or the model | +| `Skipped` | the model, when it decided the step was not needed | - - New plan dialog with Title and optional Steps, one step per line - + +`Doing` and `Skipped` exist because the model sets them as it works. You cannot reach them by clicking a step. + -## States +## Filter the list -| Filter | Meaning | -| --- | --- | -| **Draft** | Created, not started | -| **In progress** | Steps are being worked through | -| **Done** | Every step is ticked | +The list carries a status filter with four options: `All`, `Draft`, `In progress` and `Done`. The filter is applied in your browser, so it is instant, and the list itself shows at most fifty plans. -## How plans relate to other things +Each row shows how many of its steps are done, a relative timestamp, and the **From a chat** marker when the plan was spawned from a conversation. -| Object | What it is | -| --- | --- | -| **Plan** | A task list, linked to the chat it came from | -| [Project](/chat/projects) | Instructions plus chats and files | -| [Canvas](/chat/canvases) | A document beside one conversation | -| [Deep Research plan](/chat/deep-research) | The set of questions a research run will answer — a research block on the thread, not a task list | -| [Code Plan mode](/code/interactions) | A read-only mode of a Code session that proposes changes before making them | -| [CLI `/goal`](/cli/goal) | A long-horizon objective the terminal agent keeps working toward | +Two empty states tell you which situation you are in. With no plans at all: `No plans yet`, followed by `A plan turns a long answer into steps you can tick off. Create one, or ask a chat to plan the work and it will appear here.` With a filter that matches nothing: `Nothing in this status`, followed by `Try another status, or start a plan.` -## Guests and members +## When an action fails -Plans persist on a signed-in account. A guest can open the dialog, but a plan needs somewhere to live once the tab closes — sign in first. See [Accounts](/getting-started/accounts). +Every failure is a short sentence and nothing is half-applied. You will see one of `The plan could not be created`, `The step could not be added`, `The step could not be updated`, `The step could not be deleted`, `The status could not be changed`, or `The plan could not be deleted`. Retry the same action; if it keeps failing, check [status.cortex.foundation](https://status.cortex.foundation). ## Related -- [Projects](/chat/projects) — instructions that apply to every chat in them. -- [Canvases](/chat/canvases) — a document beside one conversation. -- [Deep Research](/chat/deep-research) — the research plan, which is not a task list. -- [CLI goals](/cli/goal) — a long-horizon objective in the terminal. +- [Scheduled tasks](/chat/scheduled-tasks) - run a prompt on a cadence, which is the time-based surface Planning is not. +- [Projects](/chat/projects) - standing instructions and files behind a group of chats. +- [Deep Research](/chat/deep-research) - the research plan, a brief rather than a task list. +- [Conversations](/chat/conversations) - the thread header where **Start plan** lives. +- [Built-in tools](/chat/tools) - what the model can reach while it works a plan. diff --git a/chat/plugins.mdx b/chat/plugins.mdx new file mode 100644 index 0000000..3c05882 --- /dev/null +++ b/chat/plugins.mdx @@ -0,0 +1,127 @@ +--- +title: "Connectors" +description: "Connect an app to Cortex Chat and Cortex Bot, choose where its tools appear, set when Cortex asks before it acts, and disconnect" +icon: "plug" +keywords: ["Plugins", "Customize", "Connected apps"] +--- + +**Connectors** is where you hand Cortex access to the apps you already use, so a chat can read your data and act on it. The page says so in its own lead: **Give Cortex access to your tools to read your data and act on it. You stay signed in with the provider: Cortex never sees your passwords.** Elsewhere in the product the same things are called **connected apps**, which is the plain-English name for a connector you have already set up. + +The heading on the page itself reads **Connectors**, and that is the name to look for. Elsewhere the product refers to it informally as Customize: the `/` list in the chat composer, for instance, tells you to turn a skill on **under Customize**. If you followed that wording, this is the page it meant. + +This page covers what sits on the board, how to find an app, how connecting works, how to choose which products may use it, how often Cortex asks before an app makes a change, and how to disconnect. + +## What is on the page + +The board is assembled in a fixed order: + +1. A sign-in notice, if you are browsing as a guest. +2. The **Data** card, the first-party connector for business metrics. See [Cortex Data](/chat/data). +3. The **Skills** panel, where you turn recipes on for Chat or for a bot. See [Skills in Chat](/chat/skills). +4. The connector catalogue: the apps you can connect, grouped into sections or shown as a flat grid. + + +There is no form for adding an MCP server here. Those live in **Settings** under **Integrations**. See [MCP servers](/chat/mcp-servers). + + +## Find an app in the catalogue + +Three filter pills sit above the catalogue, under the label **Filter connectors**: **Discover**, which is the default, **All**, and **Connected**. A **Category** control narrows the board to one kind of app, with **All categories** to clear it. Each Discover section shows six cards and a **Show all** link for the rest. The **Search connectors** field matches on name, and shows its own shortcut beside it: press Cmd + K, or Ctrl + K on Windows and Linux, to jump straight into it from anywhere on the page. + +Cards carry a **Verified connector** badge where the catalogue vouches for the entry, the number of tools the app brings, and a **Connect** button (**Add** with the app's name on the compact card). Once connected, the card reads **Connected** with when it happened, and **Open** with the app's name takes you to its detail drawer. A count pill at the top of the page tallies how many apps are connected. + +Nothing matched? The page answers with **No connector for** your query, then **Try another name, or browse all the categories.** and a **See all connectors** button. + +The catalogue's contents change, so browse it rather than trusting a list here. Expect the familiar categories: a code host, an issue tracker, a calendar, a cloud drive. + +## Connect an app + + + + Browse **Discover**, filter by **Category**, or search for it by name. + + + The dialog asks **Where should this app be available?** and explains: **Choose where this app's tools appear. You can change this later without connecting again.** Pick **Cortex Chat** (**Available to the assistant in a chat.**), **Cortex Bot** (**Available to your bots while they work.**), or both, then **Continue**. + + + A new tab opens on the provider's own page. Cortex never sees your password. The toast tells you what to do next: **Finish connecting** the app, then **Sign in on the tab that just opened, then come back and refresh.** + + + The card settles on **Connected**. Cortex only ever learns that a connection exists; the credential stays with the connector catalogue. + + + +Cortex asks for as little as the job needs, and says so on the card: **Cortex requests only the access needed to attach files and post messages you choose.** + +If you arrive from somewhere else in Cortex, such as a project's **Add a source** menu, the link starts that app's connect flow directly instead of dropping you on the catalogue. + + +Connecting needs an account. A guest sees **Connecting an app needs an account: a guest session cannot be signed back into to revoke it later.** and a **Sign in** button instead. + + +## Choose where an app is available + +Where an app may be used is part of connecting, not an afterthought. The connected card repeats your choice as two chips under the legend **Where this app is available**, each reading the surface name and **on** or **off**. Pressing a chip changes it, and it costs no reauthorisation. + +An app has to stay available somewhere. Turning off the last surface is refused with **Choose at least one** and the rule itself: **A plugin has to be available to Cortex Chat, Cortex Bot, or both. Disconnect the app to turn it off everywhere.** Disconnecting, not unassigning, is how you switch an app off. + +Connected apps do not reach Cortex Code. There is no Code surface for them. + +Bots have a second gate. Turning an app on for **Cortex Bot** makes it available to bots; each bot then has its own switch, and existing bots are not switched on for you when you connect something new. A bot's switch cannot be turned on while the account-level connection is off, awaiting sign-in, needs reconnecting, has failed, or is disabled, and the refusal names which. Turning a bot's switch off always works. See [Connected apps for bots](/bot/plugins). + +If a tool is called on a surface the app is not turned on for, that turn fails and tells you to turn the app on for this surface from the Connectors page. + +## Decide when Cortex asks first + +Each connected app carries an approval preference under the title **When to ask**, described as **How often Cortex confirms before a connected app makes a change.** + +| Option | What it means | +| --- | --- | +| **Always** | Ask before every mutating call. | +| **On changes** | Ask when the tool would write or send. | +| **Important only** | Ask only for high-impact writes. | + +A freshly connected app starts on **On changes**. The same preference appears elsewhere as radio buttons labelled **Always ask**, **Before changes** and **Before important actions**. + +*On changes* only ever skips a call Cortex can tell is a read. A catalogue's own "read" label can raise scrutiny but never lower it, so a writing tool still prompts. A published list of actions always asks whatever you set, and the page lists them: **These chips never cover tools that must always ask: auto-approve, opening a pull request, plugin tools as a standing grant, Design writes, nested tasks, or a git push outside cortex/*.** + +Two answers you may meet here: **This app is off for the organization and cannot be enabled here.** and **This deployment cannot store that preference yet. Cortex still asks every time.** + +## Look at what an app can reach + +**Open** on a connected card shows its detail drawer: **Connector**, **Details**, **Available in**, **Before this app acts**, and **What it can reach**. That last section is honest about its own limits: **Tools follow the approval chips. Cortex does not list folders or scopes from this app.** + +## Read a connector's status + +| Label | What it means | What to do | +| --- | --- | --- | +| **Connected** | The connection is live. | Nothing. | +| **Awaiting sign-in** | The provider tab has not been finished. | Sign in there, come back, refresh. | +| **Reconnect** | Shown with the reason **Sign-in expired**. | Connect again. | +| **Failed** | The connection did not come up. | Reconnect, or disconnect and connect again. | +| **Disabled** | It has been switched off. | Nothing you can do from this card. | + +Cards can also read **Needs sign-in** or **Available**. Failures are phrased around the app's name: it could not be connected, could not be updated, or could not be disconnected. + +## Disconnect + +**Disconnect** on the card turns the app off everywhere at once. That is the intended way to stop using it, since the surface chips refuse to leave an app with no surface at all. + +## When the catalogue is not there + +A deployment can have connected apps switched off entirely, and the page says so plainly rather than showing an empty board: + +- **Apps are not available on this deployment.** with a **Try again** button. +- **Apps are not set up here** with **Connecting apps is switched off on this deployment, so there is nothing to connect yet. Whoever administers it can turn it on.** +- **Apps cannot be listed right now** with **The list of apps could not be loaded, so there is nothing to show yet. Nothing is wrong with your account, and this usually clears by itself.** + +Some deployments also offer connector evaluation controls, **Run eval** with **Export JSON** and **Export HTML**. The report stays on your device until you export it, and secret-shaped values are stripped out of it. Where it is not offered, the answer is **Plugin eval is not available on this deployment.** + +## Related + +- [MCP servers](/chat/mcp-servers) +- [Skills in Chat](/chat/skills) +- [Cortex Data](/chat/data) +- [Page tools](/chat/page-tools) +- [Built-in tools](/chat/tools) +- [Connected apps for bots](/bot/plugins) diff --git a/chat/projects.mdx b/chat/projects.mdx index 1d91e47..d59a369 100644 --- a/chat/projects.mdx +++ b/chat/projects.mdx @@ -1,71 +1,99 @@ --- title: "Projects" -description: "A project keeps its own instructions, its chats, and its files together. Every chat in it starts from those instructions." -keywords: ["instructions", "folders", "workspace"] +description: "A project keeps standing instructions, its chats and its sources together, so every chat inside it starts from the same brief." +icon: "folder-open" --- -A **project** is a folder with standing instructions. Create one for a piece of work you keep coming back to, give it instructions once, and every chat inside it starts from them. Projects belong to a signed-in account. +A **project** is where you keep a piece of work you come back to. It holds standing **instructions**, the **chats** you file into it, and its **sources**. The product's own summary is the clearest one: a project keeps its own instructions, chats and sources together, and everything you say in its chats is read with those instructions in front of it. - - Projects — No projects yet. Create one for a piece of work you keep coming back to. - +This page covers creating a project, giving it instructions and knowledge, filing an existing chat into it, choosing which memories its chats may use, handing its context to Cortex Bot or Cortex Code, and what a project cannot do yet. Projects need a signed-in account: the product says so plainly, because a guest session cannot be signed back into to recover them. ## What a project holds -| In the project | Not a project | +| Part | What it does | | --- | --- | -| **Instructions** — read before every chat in the project | [Memory](/chat/memory) — account-wide, follows you into every chat | -| **Chats** you start inside it, or move into it | [Canvases](/chat/canvases) — a document beside one conversation | -| **Files** you add to it, from [Library](/chat/library) | [Design canvases](/design/canvases) — boards edited in the Design desktop app | -| A place in **Pinned** if you pin it | A shared workspace — projects are yours alone, see [Sharing](/chat/sharing) | +| **Instructions** | Standing guidance prepended to every chat in this project. | +| **Chats** | Conversations you start inside the project, or move in later. | +| **Sources** | Readable material every chat in the project is answered against. | +| **Memory** | A choice between account-wide memory and project-only memory. | -## Create a project +## Create a project and give it instructions - - Guests cannot create a project; the chat would have nowhere to live once the tab closes. - - Give it a **Name**. Instructions are optional and can be changed at any time. + Type a **Name** and choose **Create project**. The dialog says it itself: instructions are optional, and can be changed at any time. - - Who the audience is, house style, units, what to avoid. For example: *We sell to mid-market SaaS teams. Prices are in euros. Prefer British spelling.* + + On the project, choose **Add project instructions**, or **Edit the project instructions** if there are already some. Write the brief you would otherwise repeat: audience, house style, units, what to avoid. Choose **Save instructions**. - Open the project and start a new chat there, or move an existing thread in with **Move to project** from the thread header. + Use the project's own composer, or choose **Start chat**. The first turn is prompted with **Ask the first question in this project**, and the project offers starters such as **Summarise the sources in this project** and **Draft a plan from the instructions**. - - New project dialog with Name and optional Instructions fields - +Keep instructions short and factual. They are read before every reply, so they cost room on every reply. The header shows a one-line reminder of how many sources the project has and whether its instructions are in place. + +## Add knowledge -## Move a chat into a project +Choose **Add a source** and pick one of **Upload from device**, **Add text content**, or **Add a link**. You can also drop files straight onto the project: the drop zone says PDFs, notes and other text become sources for every chat. -Open the thread and choose **Move to project** in the header. The popover lists your projects — and **Remove from project** if the thread already belongs to one. A thread belongs to at most one project. +- **A link** is fetched by Cortex and stored as a source for the project. Cortex refreshes a link source once it is a day stale, so a page that changes does not go quietly out of date. +- **Pasted text** needs a **Title** and a body. It is stored and listed as **Pasted text**. +- **A file** can come from your device or from a file that is already in your [Library](/chat/library). Sources are chipped by kind: **PDF**, **Image**, **Code**, **Document**. +- Use the **Filter sources** control to switch between **All** and **Files**, and **Remove** on a row to take a source out. - - The Move to project popover listing projects and a Remove from project action - +Deleting a file from your Library unlinks it from any project that used it as a source, so the project stops answering against it. -## Files in a project + +Attachments belong on a chat turn, not on the project composer. If you try to attach a file there, the project tells you so and the file is not added. Add it as a source instead, or attach it inside a chat. See [Attachments](/chat/attachments). + -Add documents to a project so every chat in it can use them. Files come from your Library — attach from the composer or upload from the project — and a chat receives them as attachments, never as a URL you typed. Generated pictures land in Library too. See [Library](/chat/library). +## How instructions and sources reach an answer -## Tips +Before the model answers a turn inside a project, Cortex puts the project's instructions in front of the conversation and adds the project's readable sources. If the extracted text of those sources is small enough it is included whole, up to roughly 32,000 characters. Past that, Cortex retrieves only the passages that match your question, up to eight passages and about 6,000 characters. -- Keep instructions short and factual. They are read on every turn, so they cost context on every turn. -- One project per ongoing piece of work beats one project per topic. The point is continuity. -- Pin the two or three projects you use daily; the rest stay one click away under **Projects**. -- Plans started from a project's chats stay linked to those chats. See [Plans](/chat/plans). +Sources are always handed to the model as untrusted material. A document you added cannot give Cortex instructions, however it is worded. Only the project's own instructions do that. - -Cortex Chat is per account. Another account cannot see your projects, and there is no teammate invite on a thread. Plus and Pro plans list **Projects and saved work** among their features — check [Plans](/getting-started/plans) for what your plan includes. - +If retrieval is having trouble on a large project, the turn tells you so with **Project files unavailable** rather than answering as though the sources had been read. Retry the turn. + +## File an existing chat into a project + +Open the chat and choose **Move to project** in the thread header, then pick the project. A conversation belongs to at most one project. A **Temporary chat** has no **Move to project** and no **Pin**: those controls are hidden rather than shown greyed out. + +Pinned items are shared between conversations and projects, with room for 20 across the account. A pinned project leaves **Recents** and appears in the pinned section instead. + +## Choose which memories the project uses + +Inside the project, the **Memory** block sets whether its chats also read account-wide memory: + +- **Account memory** lets this project use memories saved across your account. +- **Project only** means only memories saved in this project are used here, and account memories stay where they are. + +Switching the scope never deletes anything. It changes what is read. See [Memory](/chat/memory) for the full surface. + +## Continue elsewhere + +The **Continue elsewhere** block hands the project's context to another product. Chat stays the home for Library, research and decks. + +- **Open in Bot** drops a summary into a bot's inbox: a short excerpt of the instructions, plus the titles, domains and kinds of the sources. The source contents are not sent. You need a bot to hand to. See [Cortex Bot](/bot/index). +- **Open in Code** opens a Cloud session from a **repository** source. A project with no repository source cannot hand off to Code. See [Cortex Code](/code/index). + +If the handoff cannot start, the project says so and nothing is changed. + +## Delete or restore a project + +**Delete project** hides the project. Restoring brings it back with its chats and its files, so a deletion is recoverable rather than final. + +## What a project cannot do yet + + +Projects are single-account today. The **Members** block states that a guest cannot be added, and an invite is refused outright rather than half-built, so there is no way to share a project with a teammate. The project's **Connected apps** block carries a **Soon** badge and is not usable yet: connect apps for Chat on the [Connectors](/chat/plugins) page instead. + ## Related -- [Library](/chat/library) — the file store projects draw from. -- [Memory](/chat/memory) — account-wide preferences, as opposed to project instructions. -- [Plans](/chat/plans) — task lists that start from a chat. -- [Sharing and teams](/chat/sharing) — what is per account, and where team features live. +- [Library](/chat/library) - the file store a project draws its file sources from +- [Memory](/chat/memory) - account-wide memory, and how a project narrows it +- [Planning](/chat/plans) - task lists started from a chat +- [Conversations](/chat/conversations) - the thread header, pinning and temporary chats +- [Sharing and teams](/chat/sharing) - what is per account today diff --git a/chat/quickstart.mdx b/chat/quickstart.mdx index 0809d10..7e5a380 100644 --- a/chat/quickstart.mdx +++ b/chat/quickstart.mdx @@ -1,38 +1,51 @@ --- title: "Chat quickstart" -description: "From an open tab to a useful first conversation — send, attach, pick a model, and keep the thread in a project." -image: "/images/banners/chat.png" -keywords: ["tutorial", "first chat", "getting started", "first message"] +description: "Send your first message, read the answer, pick a model, attach a file, and keep the thread in a project" +icon: "rocket" --- -This walk-through takes about five minutes. Steps 1–3 work as a guest; step 4 needs a signed-in account. +This walk-through takes a few minutes and starts from nothing. The first three steps work signed out, so you can try Cortex Chat before you make an account. The last three need an account, because uploads and projects belong to a signed-in user. - - The Chat composer with a multi-line prompt typed and ready to send - +You will send a message, watch the answer being written, choose the model and how long it thinks, then sign in to attach a file and file the thread away. + +## Your first conversation - - Go to [cortex.foundation](https://cortex.foundation). Chat is the default surface. Type a question in the composer and press **Enter**. + + Go to [cortex.foundation](https://cortex.foundation). Chat is what you land on, and the page greets you with **Good morning**, **Good afternoon** or **Good evening**. - ```text - Give me a three-row markdown table comparing bubble sort, merge sort and quicksort - by average time complexity and stability, then a short Python code block implementing merge sort. - ``` + Type into the box labelled **Ask anything, or pick an app below…**, or click one of the example prompts such as **Plan a 5-day trip to Tokyo**. Press Enter, or use the **Send message** button. Shift and Enter together add a line instead of sending. - The reply streams in as it is written. Tables, headings, and code blocks render as you would expect; every code block has its own **Copy**. Press **Esc** if you want to stop a response. + One message can hold up to 50,000 characters. Past 600 characters of draft the composer starts showing how much of that you have used. - - Choose **+** on the composer, then **Attach file**, or drop a file onto the composer. Type and size checks run at upload; a rejected file is not attached. Attachments land in your [Library](/chat/library), and the conversation receives the file — never a URL you typed. + + The page becomes a conversation without reloading, and the answer is written in front of you rather than appearing all at once. + + Along the way you may see a **Thinking** block that fills and then collapses to a line saying how long Cortex thought, and one-line rows for any tool it used, such as *Searched the web*. Numbered citations point at their source. + + To cut an answer short, press **Stop responding** or Escape. The card then reads **Stopped**, with **Continue** to pick the same answer back up and **Regenerate** to ask again from scratch. - Open the model chip under the text box. Choose **Cortex 1 Mini** (the default) or **Cortex Teutonic-1**, set **Thinking** to Low, Medium, or High, and switch on **Deep Research** when you want a cited report rather than a quick answer. The choice belongs to this conversation. See [Models](/chat/models). + Click the model chip under the box. It shows the name of the model in use, with no label in front of it. + + Choose **Cortex 1 Mini** or **Cortex Teutonic-1**. Both carry a **PREVIEW** badge, which is a maturity signal rather than a different service, and neither one depends on your plan. Under **THINKING**, pick **Low**, **Medium** or **High**; higher thinking spends more time before answering. + + The model belongs to the conversation and is fixed once the chat has started. To use a different one for a single message, open **This message only**; the chip then says the choice applies to your next message and that the session default is unchanged. To change the model for good, start a new chat. + + + Sign in with your Cortex account. Signing in raises your allowance and unlocks uploads, projects, memory, plans and web search, all of which a guest does not have. - - Sign in, then open **Projects** in the sidebar and choose **New project**. Give it a name and, optionally, standing instructions — they are read before every chat in the project. Start the next conversation inside it, or use **Move to project** in the header of an existing thread. + + Choose **Attach a file**, then pick a file from your computer, **From your Library**, or **Cloud drives** (a drive you have not connected yet shows **Connect**). + + The chip shows an uploading percentage and then the file name. The stated ceiling is **10 MB max**, and anything larger is refused in your browser before it is uploaded, so you do not wait for a failure. The same button that removes a file cancels an upload that is still running. + + Send the message. The file stays in your [Library](/chat/library) afterwards, and when an answer quotes it the citation names the file and the place inside it, like a page number or a sheet name. - - In the thread header choose **Start a plan**. The plan stays linked to the conversation and outlives it if you delete the chat. Track it under **Planning**. See [Plans](/chat/plans). + + Open **More chat actions** in the conversation header and choose **Move to project**, then pick one. A toast confirms with **Moved to the project**, and **Remove from project** puts it back. Projects carry standing instructions that every chat inside them starts from. See [Projects](/chat/projects). + + From the same menu, **Start a plan** turns the conversation into a checklist. The plan stays linked to the conversation and outlives it if you delete the chat. @@ -40,17 +53,37 @@ This walk-through takes about five minutes. Steps 1–3 work as a guest; step 4 | Try | Why it shows Chat well | | --- | --- | -| *Summarize this quarterly report* with a PDF attached | Documents come from Library, not a pasted URL | -| *Research the latest on …* with Deep Research on | Planned questions, live sources, a cited report | -| *Draft a launch announcement* | Long-form writing with headings; open a canvas to keep editing | -| *Plan a 5-day trip to Tokyo* | A natural candidate for **Start a plan** | +| **Summarize this quarterly report**, with a document attached | The answer cites the file and the page it read | +| A research question with **Deep Research** on | Planned questions, live sources, a cited report | +| **Draft a launch announcement** | Long-form writing you can keep editing in a canvas | +| **Plan a 5-day trip to Tokyo** | A natural candidate for **Start a plan** | +| A question that needs a table | Tables in an answer offer **Export as spreadsheet** | + +## What a guest can and cannot do + +You can hold a real conversation without an account. The sidebar shows how many free messages you have left. -## What guests can and cannot do +| | Guest | Free account | +| --- | --- | --- | +| Messages per day | 100 | 500 | +| Messages per 30 days | 500 | 3,000 | +| Uploads | no | up to 10 MB per file | +| Projects, memory, web search | no | yes | -Guests get a daily and monthly allowance (the banner above the composer shows it), can attach files to the current session, switch models, and use Deep Research. Projects, Library across sessions, memory, plans that persist, connected apps, and MCP servers need an account. See [Accounts](/getting-started/accounts). +Higher plans raise or remove the message allowance. See [Plans and quotas](/getting-started/plans) and [Accounts and sign-in](/getting-started/accounts). Anything that needs an account answers with a plain refusal and a **Sign in** action rather than failing silently. + +## Three shortcuts worth learning now + +| Keys | What it does | +| --- | --- | +| Cmd or Ctrl, then K | Open Chat search over your conversation titles | +| Cmd or Ctrl, then / | Open the shortcut sheet | +| Escape | Stop the answer being written | -## Next +## Related -- [Projects](/chat/projects) — instructions, chats, and files together. -- [Library](/chat/library) — what happens to your uploads and generated files. -- [Tools and connectors](/chat/tools) — connect an app or an MCP server. +- [Conversations](/chat/conversations) - edit, branch, pin, archive and search your threads. +- [Models and thinking](/chat/models) - the model chip and the thinking levels in detail. +- [Attachments and files](/chat/attachments) - accepted file types and how they are read. +- [How Chat works](/chat/how-it-works) - what happens inside a turn. +- [Chat troubleshooting](/chat/troubleshooting) - what a message on screen is telling you. diff --git a/chat/scheduled-tasks.mdx b/chat/scheduled-tasks.mdx new file mode 100644 index 0000000..6c3039d --- /dev/null +++ b/chat/scheduled-tasks.mdx @@ -0,0 +1,111 @@ +--- +title: "Scheduled tasks" +description: "Run a prompt on a cadence inside a conversation you already have, and read the answer in that chat like any other turn." +icon: "calendar-days" +--- + +A **scheduled task** runs a prompt you wrote, on a cadence, inside a conversation you already have. Every run lands in that conversation as an ordinary turn, so the place to read the result is the chat itself. The surface is the **Scheduled** page, and its lead says what it is for: `Run a prompt on a cadence in a chat you already have. Sharing a schedule is a different surface.` + +This page covers how to create a schedule from the Scheduled page or from a chat, the one fact that matters most (a scheduled run has no tools), where results land, how to pause, run and delete a schedule, and the limits and messages involved. + + +A scheduled run has no tools. It is one completion of your prompt: no web search, no Python, no connected apps, no memory writes, no file reads. If the answer needs any of those, run it yourself in the chat. + + +## Create a schedule + + + + + + The empty state describes the form you are about to fill: `Pick a conversation, a cadence and an instruction. The optional webhook field is not stored here.` + + + One to 200 characters. A shorter or longer name is refused with `title must be between 1 and 200 characters.` + + + A dropdown of your existing chats, starting at `Choose a conversation`. Runs land in whichever one you pick, so choose the thread where the answer belongs. + + + A five-field cron expression, prefilled `0 9 * * 1-5`. Anything else is refused with `schedule must be a 5-field cron expression, interpreted in Europe/Paris.` + + + The prompt each run sends, one to 4,000 characters. Over the ceiling you get `prompt must be between 1 and 4000 characters.` + + + The schedule appears in the list as **Active**. + + + + + + + Choose **Schedule this**. The dialog is titled **Schedule this chat**. + + + Here the cron field is prefilled `0 9 * * *`, which is different from the Scheduled page's weekday default. The hint beside it reads `Five-field cron in {timezone}.` + + + The title and the prompt are seeded from the conversation you are in, and the runs land in that same conversation. + + + + + +Reach the Scheduled page from the product navigation, and the schedule dialog from the thread header's **More** menu. + +## Times are always Europe/Paris + +The cadence is read in one timezone and only one. The dialog states it plainly: `The task runs as a Chat turn in Europe/Paris. The API stores no other timezone.` The list carries the same reminder, `Chat schedules. Times in {timezone}.` Convert your local time yourself when you write the expression. + +Cortex checks for due schedules about once a minute, and it guards against a schedule firing twice for the same slot. + +## Where results land, and what happens when a run fails + +A run posts its answer into the conversation you chose, as a normal turn, and the answer is deliberately short. Nothing is emailed, nothing is collected on the Scheduled page for you to read: the chat is the inbox. + +If a run cannot reach a model, it lands a failed result in that same conversation and stamps the reason on the schedule, so the failure shows up exactly where the answer would have been. The stable reasons are that the upstream is not configured, that no model was available, that the prompt could not be read, or that the model returned nothing. + +Each row on the Scheduled page shows the schedule's state, **Active** or **Paused**, the number of runs so far, and the last run's status. A prompt that cannot be read back is listed as `(prompt unavailable)` rather than guessed at. + +## Pause, run now, delete + +Row actions do what their labels say, and none of them touch the conversation: + +| Action | Effect | +| --- | --- | +| **Pause** | Stops the cadence. Everything else stays in place. | +| **Resume** | Starts the cadence again. | +| **Run now** | Fires the task immediately, without disturbing the cadence. | +| **Delete** | Removes the schedule. The conversation and the turns already landed stay. | + +## Limits + +| Limit | Value | +| --- | --- | +| Schedules per account | **50** | +| Name | 1 to 200 characters | +| Instruction | 1 to 4,000 characters | +| Cadence | a five-field cron expression | +| Timezone | Europe/Paris, always | +| How often Cortex checks | about once a minute | +| Tools available in a run | none | +| Answer length per run | short, about 1,200 tokens | + +The cap of 50 is account-wide and identical for everyone. The dialog's usage line reads `{used} of {limit} schedules on this plan.` and the refusal at the ceiling reads `You've reached the schedule limit on this plan.`, but the wording is misleading: no plan raises or lowers it. The server answers `A user may hold at most 50 scheduled tasks.` whatever you are subscribed to. Delete a schedule you no longer need to make room. + + +Scheduling needs an account. A guest is refused with `Sign in to schedule a task.` See [Accounts](/getting-started/accounts). + + +## The Webhook field is not saved + +The create form shows a **Webhook** field, and it tells you the truth about it: `Webhook not stored`, followed by `Sharing a schedule with a webhook is a different product surface. This field is not persisted.` Anything you type there is discarded. Sharing a schedule outward does not exist yet, so treat the field as a placeholder and ignore it. + +## Related + +- [Conversations](/chat/conversations) - the thread header with **More** and **Schedule this**, and the place every run lands. +- [Planning](/chat/plans) - task lists, the surface for what is left to do rather than when it happens. +- [Built-in tools](/chat/tools) - what a normal turn can reach, and therefore what a scheduled run gives up. +- [Chat troubleshooting](/chat/troubleshooting) - when a run lands a failure instead of an answer. +- [Limits and quotas](/reference/limits) - the rest of the ceilings across the products. diff --git a/chat/sharing.mdx b/chat/sharing.mdx index f94e2ad..bada22f 100644 --- a/chat/sharing.mdx +++ b/chat/sharing.mdx @@ -1,53 +1,94 @@ --- title: "Sharing and teams" -description: "Cortex Chat is per account. What that means for threads, projects, plans, and files — and where team features live." -keywords: ["teams", "invite", "collaboration", "privacy"] +description: "Cortex Chat is per account: what that means for conversations, projects, plans and files, and how to hand a result to someone today." +icon: "users" --- -Cortex Chat is a **per-account** product. Your threads, projects, Library, memory, and plans belong to your signed-in account and follow you across devices. Another account cannot see them, and there is no “invite a teammate to this thread” control. +Cortex Chat is a per-account product. Your conversations, projects, plans and files belong to the account you signed in with and follow you across devices. There is no team, no workspace membership, and no shared conversation: another account cannot open a thread of yours, and there is no control that invites someone into one. -## What each kind of user has +This page is the honest version of that. It covers what "per account" means for each thing a chat produces, what the **Share** button in the transcript actually does today, what a link to a single message is and is not, and the three ways you can genuinely pass a Chat result to another person right now. -| | Guest | Member | -| --- | --- | --- | -| Threads | This browser session only | Kept on the account, on every device | -| Projects, Library, memory, plans | No | Yes, private to the account | -| Connected apps and MCP servers | No | Yes, private to the account | -| Bots and Code sessions | No | Yes, private to the account | +## Who can see what + +| Thing | Who can see it | +| --- | --- | +| A conversation | only the account that created it | +| A project and the chats in it | only the account that created it | +| A plan | only the account that created it | +| A file in Library | only the account that created it | +| A link to one message | anyone with access to that conversation, which is its owner | +| An exported file | anyone you send the file to, by hand | + +The last row is the one that matters in practice. Everything inside Cortex stays with your account; the moment something becomes a file, it is yours to send like any other document. -The reasoning: a guest cannot create anything it could not come back to revoke, and a member's work is never visible to another member. +## The Share button does not produce a link -Because a guest's work lives in the browser session, signing in is what makes it survive a closed tab — the allowance, the threads, and the attachments all move onto the account. See [Accounts](/getting-started/accounts). +The transcript header has a **Share** control, and it always lands on the same state: `Sharing is not on this deployment`. Conversation sharing is not available yet, and Cortex will not invent a link it cannot honour, so you will never be handed a URL that quietly fails for the person you sent it to. -## What does not exist today + +Exporting a whole conversation as a document is not available from the app either. There is no menu item for it anywhere in Chat. To pass on a conversation's contents, export a deck from it or copy the text you need. + -- No teammate invite on a thread or a project. -- No public link for a Chat conversation. -- No shared Library between accounts. +## A link to one message is a bookmark, not access -Do not expect a sharing control to appear in the thread header — the two actions there are **Start a plan** and **Move to project**. +A message does have a link, and it is worth understanding exactly what it is for. -## Where team features live +Open a message's **Message actions** menu and choose **Copy link to message**. The dialog is titled **Link to this message** and tells you what the link does: `Opens the conversation at this message for anyone with access to it.` It adds the consequence: `Anyone without access to this conversation will be asked to sign in.` The field is labelled **Message link**, the link is marked `Expires in 7 days`, and copying it confirms with `Link copied`. -| Need | Where | +Read that carefully and the limit is clear. The link grants nobody anything. It opens a conversation at a particular message **for someone who could already open that conversation**, and because Chat is per account, that someone is you. Treat it as a deep bookmark into your own thread, which is what makes it useful for a long research conversation you want to come back to at the right spot. + +Three more things you may meet in the same menu: + +| Message | What it means | | --- | --- | -| A team workspace with admin controls, SSO, and audit export | The **Pro** plan lists these — see [Plans](/getting-started/plans) | -| Sharing a coding session transcript | The CLI can share a session with `/share` or `cortex run --share` — see [CLI sessions](/cli/sessions) | -| Reviewing a pull request with colleagues | [Cortex Security](/code/security) posts its review as a GitHub check run on the pull request | +| `Copy message text` | the other item in the menu: it copies the message body to your clipboard | +| `Sharing is not available for this message yet.` | a link to this particular message could not be built | +| `The link could not be copied.` | the clipboard write failed; try again | + +## How to share a Chat result today -The pattern is consistent: the surfaces that involve other people are the ones attached to a repository, a session transcript, or a plan tier — not a conversation. That is deliberate. A thread carries whatever you happened to paste into it, so there is no link that would hand it to someone else. +Three routes work, and all of them end with you sending something yourself. + + + + From an answer, choose **Export** to build a deck from an editable outline; from the transcript header, **Export as deck** does the same for the whole thread. The file is saved to [Library](/chat/library) and can be downloaded. See [Export documents](/chat/document-export). + + + The answer's action row has **Copy**, which becomes `Copied` on success and `Copy failed` if the clipboard write is refused. This is the fastest way to move a paragraph into an email or a ticket. + + + When an answer contains a table, the **Export as spreadsheet** link under it downloads the rows as a comma-separated file immediately, with no dialog and no allowance spent. + + + +A note saved from a selection, through **Save to Library**, is worth mentioning here because its own wording invites confusion: `Saved in Chat Artifacts. Available from Chat, Code and Bot.` That means the note is reachable from your other Cortex products, not by other people. It is cross-product, not cross-account. + +## Signed out versus signed in + +You can use Chat without an account. What changes when you sign in is scope and durability, not who else can see your work. + +| | Signed out | Signed in | +| --- | --- | --- | +| Conversations | a working chat with a smaller allowance | kept on the account, across devices | +| File uploads | not available | available, within the attachment limit | +| Projects | not available | available, private to the account | +| Web search | not available | available | +| Exporting a deck | available, with the smallest daily allowance | available, per your plan | -## What a signed-in account does share +While you are signed out, the sidebar keeps a count of the free messages you have left. Anything that needs an account refuses with an entitlement message and a **Sign in** action rather than failing silently. See [Accounts and sign-in](/getting-started/accounts) and [Plans and quotas](/getting-started/plans). -Nothing between accounts, but a lot between your own devices. Your threads, projects, Library, memory, plans, and Bot routines follow the account, which is why signing in is what makes them persist at all. See [Accounts](/getting-started/accounts). +## Where collaboration does exist -## Export and deletion +Nothing in a conversation is shared, and that is deliberate: a thread carries whatever you happened to paste into it. The sharing surfaces Cortex does have live outside a conversation, and these are the pages that describe them: -Your data is yours to take or remove. **Settings → Data & privacy** offers **Export my data** and **Delete all data**; a signed-in account confirms with an authenticator app. See [Security](/security/overview) and [Accounts](/getting-started/accounts). +- [Sharing files and connected drives](/chat/library-sharing) +- [Share a bot](/bot/sharing) +- [Pull-request review](/code/security) ## Related -- [Accounts](/getting-started/accounts) — guest versus member. -- [Projects](/chat/projects) — private to your account, with no invite control. -- [Plans and quotas](/getting-started/plans) — where team workspace features are listed. -- [CLI sessions](/cli/sessions) — sharing a session transcript from the terminal. +- [Accounts and sign-in](/getting-started/accounts) for what signing in changes. +- [Export documents](/chat/document-export) for the file you actually send. +- [Conversations](/chat/conversations) for the rest of the transcript header actions. +- [Data and privacy](/getting-started/data-and-privacy) for what is stored and for how long. +- [Plans and quotas](/getting-started/plans) for the allowances behind each plan. diff --git a/chat/skills.mdx b/chat/skills.mdx new file mode 100644 index 0000000..a2245e6 --- /dev/null +++ b/chat/skills.mdx @@ -0,0 +1,88 @@ +--- +title: "Skills in Chat" +sidebarTitle: "Skills" +description: "A skill is a short recipe the model loads when it applies. Some ship with Cortex; the ones you write are scanned before they can be enabled." +icon: "graduation-cap" +--- + +A **skill** is a recipe: a short Markdown document that tells the model how to do one kind of job well. The catalogue says it in one line, `Import SKILL.md or browse the catalogue. Skills are recipes, not connectors.` That distinction matters. A skill carries knowledge and method; it grants access to nothing. Connecting an app is a different action with different consequences, covered in [Connectors](/chat/plugins). + +This page covers how a skill reaches the model during a turn, the skills that ship with Cortex, turning on a skill of your own, the scan every authored skill goes through, writing or importing one, and using one in a chat. + +## How the model loads a skill + +The conversation does not start with every skill's text loaded. Cortex puts a one-line index of the available skills in front of the model. When the model decides that one of them applies to what you asked, it fetches that skill's body, reads it, and then answers. This is why having many skills turned on does not make a turn slower. + +The index is also filtered by what the turn can actually do. A skill that declares it needs a tool which is not available in this turn is left out of the index entirely, so the model is never shown a recipe it could not follow. + +## Skills that ship with Cortex + +Some skills are first-party: they ship with the product, they are always available, they are always enabled, and they have no switches to find. They are much of what makes Chat behave well without being asked: citing sources properly, writing a good picture prompt, running an origin check, laying out a readable table, working with your connected business metrics, using the Python sandbox sensibly, reviewing code, researching on the web, and writing clean Markdown. + +On the **Skills** catalogue these carry the badge **First-party**. Use the filters to move between **Discover**, which is the default view, **All**, and **Installed**; anything you have added shows the **Installed** badge. + + +A few skills exist for other runtimes and never appear in a chat, because they need tools only that runtime registers. If a skill is not in the `/` list, the reason is usually that, or that it is not turned on for Chat. + + +## Turn on a skill of your own + +Your own skills, whether you wrote them or imported them, are managed from the **Skills** panel on the **Connectors** page. Its own description is `Recipes you write and turn on for Chat or for a bot. Each one is scanned before it can be enabled.` + +Each authored skill has **two switches, one per surface**: one for **Cortex Chat** and one for **Cortex Bot**. They are separate on purpose, because those are different runtimes with different reach. Turning a skill on for Chat says nothing about whether a bot may use it. + +When a skill has been scanned cleanly, the row says `No findings. The static check ran and the review agreed.` and the switches behave normally. Where the scan flagged something, or did not run at all, the row offers `Review for {surface}` and, once you have read the findings, `Enable for {surface} anyway`. The acknowledgement travels with the enable: you are choosing, on the record, to run a recipe that was not cleared. + +## What the scan looks for + +Every authored skill is scanned before it can be enabled. The scan looks for a specific, short list of problems rather than judging style. + +| Finding | What it means | Severity | +| --- | --- | --- | +| Prompt injection | Text written to steer the model against your instructions. | Critical | +| Data exfiltration | Instructions to send your data somewhere. | Critical | +| Secret in the body | A credential pasted into the document. | Warning | +| Remote execution | Instructions to run code fetched from elsewhere. | Warning | +| Privilege escalation | An attempt to widen what the turn is allowed to do. | Warning | +| Work outside the workspace | Reaching outside the files and folders in scope. | Warning | +| Obfuscated payload | Content hidden so a reader cannot see what it does. | Warning | + + +A clean scan is not a grant, and an unscanned skill is not a safe one. Where the review did not run, the panel says so: `The review did not run, so this recipe has not been cleared. Enabling anyway is your call.` Read the findings before you accept them. + + +## Write a skill + +Choose **New skill** in the Skills panel and write a Markdown document. The frontmatter is deliberately narrow: you may declare only **name**, **description**, **version** and **tags**. Any other key is refused outright, and the refusal names the key it rejected rather than quietly dropping it. + +Two other things are refused before the document is ever sent: a URL that is not `https`, and a missing required field. Content in the body is treated differently. A body with something questionable in it does reach the server, is scanned, and the findings are shown to you, because the choice of whether to enable it is the owner's to make. + +## Import a skill + + + + Choose **Import SKILL.md**. + + + Cortex reads the file's text and shows you a confirm step before it sends anything, so you can see exactly what you are about to install. + + + The server parses and validates the frontmatter before storing it. Nothing guesses a name for you and nothing repairs an invalid document. + + + +Then enable it per surface, the same as a skill you wrote yourself. + +## Use one in a chat + +Type `/` in the composer to list the skills you have turned on for Chat, pick one, and write your message as usual. The picker notes that only skills turned on for Chat appear there, and its hint tells you to turn one on `under Customize` - the page it means is [Connectors](/chat/plugins), which is that surface's own title. The footer explains what happens next: `The message is sent with the skill named, and the agent loads it before it answers.` + +Skills need a signed-in account. For a guest the list is not fetched at all, and the panel shows a sign-in prompt instead of an empty catalogue. + +## Related + +- [Connectors](/chat/plugins) holds the Skills panel and the connected-app catalogue. +- [Built-in tools](/chat/tools) covers the tools a skill can call during a turn. +- [Bot skills](/bot/skills) covers the same recipes on the other surface. +- [Skills in the CLI](/cli/skills) covers skills in the terminal. +- [Chat troubleshooting](/chat/troubleshooting) covers a skill that is not offered in a turn. diff --git a/chat/streaming.mdx b/chat/streaming.mdx index 19d512d..b929d8d 100644 --- a/chat/streaming.mdx +++ b/chat/streaming.mdx @@ -1,48 +1,94 @@ --- -title: "Streaming" -description: "Answers appear as they are written — tokens, then tools, then the finished reply. If the connection drops, the thread reconnects; you do not resend." -keywords: ["tokens", "live reply", "reconnect"] +title: "Streaming and reconnects" +description: "Answers arrive in pieces as they are written, you can stop or steer them, and a dropped connection resumes instead of starting over" +icon: "bolt" --- -Chat streams. You see the answer being written rather than a block of text after the turn ends, and you can stop it at any point. +An answer in Cortex Chat is not one response that appears when it is finished. It is a live sequence of small pieces: words, thinking, tool rows, citations, files and, at the end, a reason the turn stopped. You can read along, interrupt, and pick up where the answer left off. - - A Chat thread while a reply is in flight — Cortex is responding - +This page covers what appears while an answer is being written, how to stop and resume one, what happens when your connection drops or you go offline, and why an error can turn up part way through an answer that started normally. -## What streams, in order +## What you see while an answer is written -| Phase | What you see | +| On screen | What it means | | --- | --- | -| Thinking | A blinking caret while the model reasons; longer at higher [thinking levels](/chat/models) | -| Tokens | The reply appearing word by word, markdown rendering as it lands | -| Tools | Tool results entering the thread when the model uses one | -| Finished | **Copy**, **Listen**, and feedback controls under the reply | +| Words appearing a few at a time | The answer is being written right now | +| A **Thinking** block filling, then collapsing to a duration | The model reasoned first. See [Models and thinking](/chat/models) | +| A short row such as *Searched the web* | A tool ran. The row then shows how it ended | +| A numbered citation with its source | The claim above it came from there | +| A file card | Cortex produced a file, and it is in [Library](/chat/library) | +| An image, a chart or a data dashboard | Cortex generated that block inside the answer | +| A provenance verdict | An origin check finished, see [Check origin](/chat/origin-check) | +| A short notice on the answer | Cortex added a safety or disclosure note | +| A marker saying earlier messages were summarised | The conversation was compacted to make room | +| The document rail refreshing on its own | Cortex is writing into a [canvas](/chat/canvases) | +| A permission prompt | Something needs your approval before it runs | -A turn can pass through the tool phase more than once. The model asks for a tool, Chat runs it, the result enters the thread, and the model keeps writing — until it stops or reaches Chat's round budget. That is the loop described in [How Chat works](/chat/how-it-works), and it is why a turn that uses a tool takes longer to look finished than one that does not. +While this is happening the composer reads **Cortex is responding…** and the send button becomes **Stop responding**. -A [Deep Research](/chat/deep-research) run streams differently: each planned question is a background child, so the thread fills from several sources at once rather than one reply growing word by word. +A tool row's label is deliberately short and human. A long tool result is shortened for display, and the row says how much was cut. The compaction marker tells you how many earlier messages were summarised but does not show the summary itself: your original messages stay in the transcript, and the summary is what the model reads in their place. [How Chat works](/chat/how-it-works) explains when that happens. -## Stop a response +## Stop an answer and pick it back up -Press **Esc**, or the stop control where the send button was. The partial reply stays in the thread. See [Keyboard shortcuts](/getting-started/settings#keyboard-shortcuts). +| Action | What happens | +| --- | --- | +| **Stop responding**, or `Esc` | The turn ends immediately and whatever was written stays. The card is marked **Stopped** | +| **Continue** | Picks that same answer back up in place, with the hint **Pick up the answer where it stopped.** Offered only on a stopped answer | +| **Regenerate** | Asks for the answer again. The previous one is kept as a version and a pager appears | + +Nothing is destroyed by stopping or regenerating. Only one live answer can exist in a conversation at a time, which is why regenerating or editing during a live turn is refused with **Wait until the current answer finishes.** Attempting a second answer anyway raises [Concurrency limit reached](/problems/concurrency_limit_reached). + +**Continue** is only ever offered on an answer that stopped. On anything else it answers **That answer cannot be continued.**, and regenerating is the right move instead. [Conversations](/chat/conversations) covers versions and branches in full. + +## Steer or queue while it writes + +You do not have to wait in silence for a long answer. + +- **Steer this reply** sends a correction into the answer that is being written. The placeholder says what it is for: **Steer while Cortex is still writing…** +- **Queue a follow-up…** parks your next message instead. It shows as a **Queued follow-up** chip and is sent when the current answer finishes. + +A queued follow-up can be taken back with **Return queued follow-up to the composer**. Only the owner of the conversation can do that, and anyone else gets **Only the owner can return this follow-up.** ## When the connection drops -Run state lives in the thread, not in the transport. If your connection drops mid-reply, the product reconnects and the reply that already started continues. **Do not resend** the same message to recover it — you would start a second turn. +The answer is produced on Cortex's side and buffered as it is created, before any of it reaches your browser. Your browser keeps track of how much it has received. If the connection drops it reconnects, says where it stopped, and the rest is replayed to it. + +What you see is **Reconnecting**, gaining an attempt number from the second try onwards, together with **The answer picks up where it stopped.** Then the words carry on from where they were, rather than starting over. -## Queueing + +Reloading the page during an answer does not lose it. The work continues on Cortex's side, so a reload shows the answer still being written, or finished. Do not resend the same message to recover an answer in progress, because that starts a second turn. + + +The resumable window is generous but not endless. Once a turn's buffer is gone, Chat says **This stream is no longer resumable. Reload the conversation.** Reloading then shows the finished answer if the turn completed on its own. That state is reported as [Gone](/problems/gone). + +## When you are offline + +Losing the network before you send is handled separately from losing it during an answer. The composer switches to **You are offline — your message will wait here** and holds your text. A toast confirms **Sending when back online**, and the message goes out when the connection returns. + +One thing to watch: the wait is tied to the chat you are in. If you navigate away with a message still waiting, it is dropped, and you are told rather than left to wonder: **A waiting message was discarded because you left this chat.** + +## Tool rows and the round budget + +A turn can pass through the tool phase more than once. The model asks for a tool, Cortex runs it, the result enters the transcript, and the model keeps writing. That loop is bounded, which is why a turn that uses tools looks unfinished for longer than one that does not. + +| Bound | Value | +| --- | --- | +| Tool rounds in one Chat turn | 8 | +| Tool calls in one turn, hard ceiling | 50 | +| Identical calls tolerated before the loop breaks | 6 | -Sending while a reply is still streaming is not the intended path in the web app; wait for the reply or stop it first. The CLI queues follow-ups explicitly — see [The TUI](/cli/tui). +None of these ends the turn silently. When the round budget runs out the model is asked to answer with what it already has, or to say how it would like to proceed. When the same call repeats without getting anywhere, the loop is broken with **The same tool call repeated without progress. Try a different action.**, and rephrasing the request is usually the fix. -## Where the answer is written +## Why an error can appear inside a good answer -Streaming is the transport, not the record. The thread holds the run state, which is why a dropped connection can resume the reply it already started and why a partial reply survives a stop. The same thread is what the [Library](/chat/library) fetch and the **Copy**, **Listen**, and feedback controls attach to when the reply finishes. +By the time something fails, the response has usually already started. The failure therefore arrives as part of the answer rather than as a refusal before it, which is why an answer can begin normally and then show an error card part way down. The card carries a code, and every code has a page under [Problems](/problems). -Long threads are compacted on the request path so they keep fitting the model. Compaction keeps the last ask, an active research plan, and open artifact ids — it does not keep every word you ever typed. See [How Chat works](/chat/how-it-works). +If a turn fails after your allowance was charged, the allowance comes back and you see **Generation failed. Your allowance for this message has been returned.** A turn that was cut short instead reports **The action was interrupted.**, and **Continue** or **Regenerate** takes it from there. ## Related -- [How Chat works](/chat/how-it-works) — the loop behind the stream. -- [Voice](/chat/voice) — **Listen** appears once the reply is finished. -- [Chat troubleshooting](/chat/troubleshooting) — a reply cut short, and what not to do about it. +- [How Chat works](/chat/how-it-works) - the turn loop behind the stream. +- [Conversations](/chat/conversations) - versions, branches and editing a sent message. +- [Models and thinking](/chat/models) - what decides how long the thinking phase lasts. +- [Voice](/chat/voice) - **Listen** appears on an answer once it is finished. +- [Chat troubleshooting](/chat/troubleshooting) - the messages a broken turn leaves behind. diff --git a/chat/tools.mdx b/chat/tools.mdx index bd44762..86342b5 100644 --- a/chat/tools.mdx +++ b/chat/tools.mdx @@ -1,90 +1,103 @@ --- -title: "Tools and connectors" -description: "Built-in Chat tools, connected apps under Customize → Connectors, GitHub in Settings → Integrations, and MCP servers." -keywords: ["Customize", "Connectors", "integrations", "plugins", "MCP", "connected apps"] +title: "Built-in tools" +description: "How a Chat turn reaches past the model: web search and reading, a Python sandbox, memory, stored results, and the tools you add yourself." +icon: "screwdriver-wrench" --- -A Chat turn can call tools. Some are built in — web search, Python snippets, image generation, memory, canvases. Others come from apps you connect, and from MCP servers you attach. This page explains where each lives and how to scope it. +Tools are how a turn in Cortex Chat reaches past the model: searching the web, reading a page, running a snippet of Python, reading one of your own files, remembering something, drawing a chart from your metrics, or calling an app you connected. Some are built in and always there. Others appear only because of something you set up, and some exist only where the deployment supports them. - - Connectors — search connectors, Discover / All / Connected, apps grouped by category - +There is no tools page inside the product to switch these on. A tool shows up as a row inside the answer while it works, and disappears into the result when it finishes. This page covers what is built in, why a tool is sometimes simply absent, what happens to a tool's result before the model sees it, the Python sandbox in detail, and where the tools you add yourself come from. -## Built-in tools +## What is built in -| Task | What Chat uses | Guide | +| Tool | What it does | More | | --- | --- | --- | -| Find current information | Web search and web extraction | [Deep Research](/chat/deep-research) for a full cited run | -| Work through a calculation or transform data | A Python snippet sandbox | [How Chat works](/chat/how-it-works) | -| Create a picture | Cortex-Image-1 | [Image generation](/chat/images) | -| Check attached media | Origin check | [Origin check](/chat/origin-check) | -| Remember a preference across chats | Memory | [Memory](/chat/memory) | -| Draft a document beside the chat | A canvas | [Canvases](/chat/canvases) | -| Read a large attachment | Artifact read and search tools | [Library](/chat/library) | +| Web search | Looks things up on the live web | [Deep Research](/chat/deep-research) for a full cited run | +| Reading a web page | Opens a page and extracts its text | [Deep Research](/chat/deep-research) | +| Python in a sandbox | Runs a short snippet for arithmetic, data frames, plots or checking code | the section below | +| Current time | Tells the model what time it is now | | +| Loading a skill | Pulls in the full text of a skill it decided to use | [Skills in Chat](/chat/skills) | +| Reading a stored result | Reads a result that was too large for the conversation | the section below | +| Searching a stored result | Searches inside that stored result instead of re-reading it | the section below | +| Writing and reading a canvas | Drafts a document beside the conversation | [Chat canvases](/chat/canvases) | +| Saving a memory | Stores a standing preference or fact, when memory is on and the chat is not temporary | [Memory](/chat/memory) | +| Forgetting a memory | Removes one | [Memory](/chat/memory) | +| Reading one of your Library files | Reads a file you own, and only a file you own | [Library](/chat/library) | +| Generating an image | Draws a picture | [Image generation](/chat/image-generation) | +| Checking origin | Checks whether an attached photo or clip is authentic | [Origin check](/chat/origin-check) | +| Business metrics | Queries a metric, investigates it, or writes a dashboard, once a metrics source is connected | [Cortex Data](/chat/data) | -Chat's Python tool runs a small snippet with no workspace. It is not Code's shell inside a Cloud guest and not Bot's computer. +Searching your past chats exists as a capability behind an explicit consent, but that consent is not exposed anywhere in the product yet, so no chat can use it today. -## Connected apps + +Tools and reasoning are not metered. There is no tool quota and no tool meter on any plan, so a turn that needs six searches and two Python runs costs you nothing extra in allowances. + -Open **Customize** in the sidebar (the page is titled **Connectors**). Apps are grouped by category — accounting, ads, CRM, and so on — with **Discover**, **All**, and **Connected** filters and a search box (⌘ K). +## When a tool is not offered + +A tool is only offered when it can actually run. Web search appears only where a search stack is configured. Python appears only where an executor exists. Business metrics appear only once a metrics source is connected. + +Where one of those is missing, the tool is not registered at all. You do not get a broken tool or an error row, you simply never see it offered. If you expected a capability and the model says it cannot do it, the honest answer is usually that the tool is not available on your deployment rather than that the model refused. + +## What happens to a tool result + +Every result is handled the same way, whichever tool produced it, and in this order. - - Connecting an app needs an account: a guest session cannot be signed back into to revoke the connection later. + + Before the model reads it. - - Choose the app and follow its own sign-in. You stay signed in with the provider; Cortex never sees your passwords. + + It is truncated from the middle, keeping the beginning and the end, at around 24,000 characters. - - Each connection can be available to **Cortex Chat**, **Cortex Bot**, or both. A connection enabled only for Bot is not a Chat tool, and Bot never inherits a tool you did not assign to it. + + Past roughly 64,000 characters the result never enters the conversation. It is stored as an **artifact**, the model is handed a short stub and an id, and it gets two tools for working with it: it can read the artifact and search it. That is how a huge page or a huge query result stays usable without flooding the thread. + + + Text inside a web page or a document cannot act as an instruction to the model. -Connected apps are read at question time. Their content is never stored by Cortex — see [Security](/security/overview). - -## Integrations in Settings - -**Settings → Integrations** lists the apps that add tools directly to your conversations. GitHub is live with four tools — list pull requests, list issues, create issue, and more. Linear, Slack, Notion, and Vercel are shown as coming soon. The GitHub connection is the same one Code uses for repositories; see [Connect GitHub](/code/github) for the walk-through. +A tool call ends in one of five ways: it succeeded, it errored, it timed out, it was refused, or it was interrupted. A row that produced nothing at all reads **No output.** -## MCP servers +## The Python sandbox -Cortex Chat is a Model Context Protocol client. Under **Settings → Integrations → MCP servers**, attach a server over HTTP: a name, its URL, and an optional bearer token. Its tools join the model in chat alongside built-in tools and connected apps. You must be signed in. +Chat's Python tool is a snippet sandbox, not a build machine. It has **256 MiB** of memory, **no network**, and a few minutes of wall clock. It is the right tool for arithmetic, a data frame, a plot or checking a piece of code, and the wrong one for installing packages or building a project. - - MCP servers — name, https URL, bearer token (optional), Add - +Two practical rules: -| Field | Notes | -| --- | --- | -| **Name** | How the server appears in chat, for example `linear` | -| **URL** | The server's HTTP endpoint, for example `https://mcp-server.example.com/mcp` | -| **Bearer token** | Optional. Sent with each request to the server; never shown again. | +- **Print what you want to see.** The last value is discarded, so a bare expression on the final line gets you nothing. +- **Files the run writes to its `outputs/` folder are collected into your Library** when the run finishes. Direct files only, at most 10 files and 10 MiB in total. A run that failed collects nothing. -The CLI is also an MCP client, with stdio and HTTP transports and its own configuration — see [Extend the CLI](/cli/extend). +If you need a shell, a repository and a real workspace, that is [Cortex Code](/code/index), not a chat. -## GitHub repositories belong in Code +## Skills are loaded, not always on -Connecting GitHub for **Code repositories** is a different control: **Connect GitHub** on Code Home, in the repository picker, or under **Settings → Integrations**. There is no personal-access-token field. If the connection lapses the product shows **Reconnect**; if GitHub is unavailable on your deployment, the control is not shown. See [Connect GitHub](/code/github). +Skills are recipes the model can pull in. It does not carry them all at once: it sees a one-line index of the skills available to it, and fetches the full body of one only when it decides to use it. That is why a skill can change how an answer is written without you naming it in the prompt. Typing `/` in the composer lists the skills turned on for Chat. -Cortex Security's GitHub App — pull-request review — is a third, separate install. See [Cortex Security](/code/security). +## Tools you add yourself -## Frequently asked +Everything above is built in. Three more sources of tools are yours to set up, and each has its own page. - - - You are a guest. The banner on the Connectors page explains it: connecting an app needs an account so the connection can be revoked later. - - - Connections are scoped per product. Open **Customize → Connectors** and enable it for Chat as well. - - - No. Connected-app content is read at question time and discarded. See [Security](/security/overview). - - + + + Connect an app and choose whether its tools reach Chat, Bot, or both. + + + Attach a remote server and its tools join the turn alongside the built-in ones. + + + Tools a web page declares, each one granted or denied by you. + + + The bundled recipes, turning one on, and writing your own. + + ## Related -- [How Chat works](/chat/how-it-works) — how tools enter a turn. -- [Connect GitHub](/code/github) — the repository connection, which lives in Code. -- [Cortex Security](/code/security) — the third GitHub install, for pull-request review. -- [Extend the CLI](/cli/extend) — MCP servers for the terminal agent. +- [How Chat works](/chat/how-it-works) - how a turn is assembled and how tools enter it. +- [Library](/chat/library) - where stored results and sandbox outputs end up. +- [Deep Research](/chat/deep-research) - a research run, which replaces the ordinary tool loop. +- [Scheduled tasks](/chat/scheduled-tasks) - runs that get no tools at all. +- [Models and thinking](/chat/models) - the chip where thinking and Deep Research are switched. diff --git a/chat/troubleshooting.mdx b/chat/troubleshooting.mdx index 2262c4d..2b93227 100644 --- a/chat/troubleshooting.mdx +++ b/chat/troubleshooting.mdx @@ -1,67 +1,167 @@ --- title: "Chat troubleshooting" -description: "What Chat shows when a turn, a file, a model, or a connection does not behave — and what to do about it." -keywords: ["errors", "problems", "fixes", "not working"] +description: "The messages Chat shows when a send, an answer, a file, a document, a limit or a search does not go through, and what to do about each." +icon: "life-ring" --- -Chat says what is wrong in plain words rather than spinning. This page maps those messages to causes and fixes. For the whole app, see [Troubleshooting](/getting-started/troubleshooting); for the terminal, [CLI troubleshooting](/cli/troubleshooting). +Cortex Chat says what is wrong in plain words rather than spinning or guessing. That makes most problems self-explanatory once you know which message belongs to which situation, which is what this page is for. -## The reply +Everything below is grouped by what you were trying to do when the message appeared: send, wait for an answer, run a tool, attach a file, hit a limit, make a document, search, or tidy up a chat. Each entry gives the message you see, what it means, and what to do next. -| What you see | Cause | Fix | +## Why a control is sometimes missing rather than greyed out + +Before the messages, one rule explains a whole class of confusion. When a capability is not available to you, Cortex removes the control instead of disabling it. That is why the read-aloud button, the microphone, the save-to-drive button and the thinking selector are sometimes simply not there. A missing control means "not available here", not "broken". Expect controls to appear when they can do the work, rather than to sit greyed out. + +## Sending a message + +| What you see | What it means | What to do | | --- | --- | --- | -| A reply cut short, then the thread reconnects | The connection dropped mid-reply | **Do not resend.** Run state lives in the thread; the reply that already started continues. See [Streaming](/chat/streaming). | -| The send button stays a stop control | A turn is in flight | Wait, or press **Esc** to stop it. The partial reply stays. | -| A long thread answers more vaguely than it did | The thread was compacted to fit the model's context window | Start a new chat, or put the standing detail in a [project](/chat/projects) so it is not repeated. See [How Chat works](/chat/how-it-works). | -| A turn fails with [`service_unavailable`](/problems/service_unavailable) | Compaction could not summarise the thread | Retry. Compaction fails closed rather than dropping your earlier turns. | +| `The message is empty.` | there was nothing to send | type something first | +| `The message is longer than the permitted maximum.` | one message can carry up to 50,000 characters | split it, or attach the text as a file | +| `You are offline — your message will wait here` | no network; the draft is held, not lost | wait; you will also see `Sending when back online` | +| `A waiting message was discarded because you left this chat.` | you navigated away while a message was queued offline | retype it in the chat you meant to send it from | +| `Loading the available models.` | the model list has not arrived yet | wait a moment, then send | +| A reason followed by `Sending is unavailable until the model list loads.` | the model list could not be fetched | retry; sending unblocks once the list loads | +| `No models are available on your account.` | no model is offered to this account at all | check [Plans and quotas](/getting-started/plans), and [status.cortex.foundation](https://status.cortex.foundation) if it persists | -## Files and images +## Waiting for an answer -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| A file will not attach | Type or size check failed at upload | A rejected file is not attached and does not enter Library. Try a supported type or a smaller file. | -| An error square where an image should be | The Library fetch or the generation failed | Retry the request. It is never an endless spinner. | -| **Improving prompt…** on an image card | The picture is queued; Chat is completing the scene description first | Wait — the card becomes a skeleton, then the image. | -| A generated picture is missing from the thread | It saved to Library but the fetch failed | Open [Library](/chat/library) and attach it from there. | -| Image generation is unavailable | The deployment has image generation switched off | The request fails closed before any quota is spent. See [Image generation](/chat/images). | +| `Reconnecting`, then the same word with an attempt count | the connection dropped mid-answer | nothing; the card adds `The answer picks up where it stopped.` and the words continue from where they were | +| `This stream is no longer resumable. Reload the conversation.` | too much time passed to pick the stream back up | reload the page; if the answer finished server-side, you will see it in full | +| `Generation failed. Your allowance for this message has been returned.` | the model failed part-way through the turn | send it again; nothing was charged | +| `The action was interrupted.` | the turn was cut short | continue the answer, or regenerate it | +| An error card in the middle of a finished-looking answer | the failure happened after the answer had begun, so it arrives inside the answer rather than instead of it | read the code on the card and look it up in the [Problem catalog](/problems) | + +Reloading the page during an answer does not lose it. The answer is produced on Cortex's side and buffered, so a dropped tab, a reload or a flaky connection does not cost you the turn. See [Streaming and reconnects](/chat/streaming). -## Models and research +Two endings are worth telling apart. An interrupted turn is either your own stop or a client that went away. A turn that ended on length hit the wall clock or the model's output ceiling, in which case continuing it is usually what you want. -| What you see | Cause | Fix | +## Stopping, continuing, regenerating and branching + +| What you see | What it means | What to do | | --- | --- | --- | -| The model on the chip is not the one you picked | Peak-hour fallback, or the conversation kept the model it was created with | Check the chip: it always names the model serving the conversation. See [Models](/chat/models). | -| A model is missing from the chip | Availability depends on your plan | Compare plans under **Settings → Plan & billing**. See [Plans](/getting-started/plans). | -| **Deep Research** is missing | You are in Code or Bot | Deep Research is a Chat feature. Switch to Chat. | -| A research run stops early | A per-run cap was reached | Questions, sources, and parallelism are capped per run. See [Deep Research](/chat/deep-research). | -| Origin check says it cannot run | The check is unavailable on this deployment | Ask again later. Cortex says so rather than guessing — do not read silence as a verdict. See [Origin check](/chat/origin-check). | +| `Stopped` on the answer card | the turn ended early and kept what it had written | use **Continue** (`Pick up the answer where it stopped.`) or **Regenerate** | +| `That answer cannot be continued.` | this answer did not end in a way that can be resumed | regenerate instead | +| `There is no answer to continue in a new conversation.` | there is nothing before this point to pick up | send a message first | +| `Wait until the current answer finishes.` | you tried to edit or branch while an answer was live | wait for the answer, then edit; only one live answer can exist in a conversation | +| `Branching from a message is not on this deployment.` | the branch action is not served here | copy what you need into a new chat | -## Voice +Regenerating never deletes anything: the previous answer is kept as a version, and a pager appears above the answer so you can step between them with **Previous version** and **Next version**. Editing one of your own messages keeps the original too, under the banner `Editing · original kept as Branch 1`. + +## Tools inside an answer + +| What you see | What it means | What to do | +| --- | --- | --- | +| `No output.` on a tool row | the tool ran and returned nothing | usually harmless; the answer continues | +| A row naming a tool that failed, with the detail it returned | one tool failed | the answer continues without it; rephrase if the missing step mattered | +| `The same tool call repeated without progress. Try a different action.` | the same call repeated six times with no progress, so the loop was broken | rephrase the request, or narrow it | +| `The tool call budget for this turn (50) is exhausted. Answer with what you have, or ask the user how to proceed.` | the turn reached its ceiling on tool calls | ask a narrower question, or split the work over two messages | +| `Tools are not configured on this process.` | this deployment has no tools wired | not a user error; ask without tools | + +A Chat turn gets eight rounds of tool use and at most 50 tool calls. When the round budget runs out the model is told so and asked to answer with what it has, which is why a long research-shaped question can end with a summary rather than more searching. See [Built-in tools](/chat/tools). + +## Attaching a file + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Upload failed` | the upload did not complete | retry from the attach button | +| `That file is larger than the attach limit.` | over the composer's ceiling, which is shown as `10 MB max` | compress it, split it, or paste the relevant part as text | +| `That file is not an image or video the composer can attach.` | the image and video rail only takes media | use the general attach button for documents | +| `That file is encrypted or unreadable. Cortex did not extract it.` | the file could not be read, so nothing was extracted from it | remove the protection, or export an unencrypted copy | +| `HEIC photos can be checked for origin. Use Check origin, or convert to JPEG or PNG.` | that photo format is accepted for origin checking only | convert it, or use [Origin check](/chat/origin-check) | +| A chip stuck on a reading state, naming the file | text is still being extracted | wait; the chip settles into the file name | + +The size check runs in the browser before anything uploads, so an oversized file is refused straight away rather than after a long wait. Signed-out use cannot upload at all. See [Attachments and files](/chat/attachments). -| What you see | Cause | Fix | +## Running into a limit + +| What you see | What it means | What to do | | --- | --- | --- | -| No mic in the composer | The deployment cannot transcribe | Nothing to configure — the capability is off, not broken. | -| No **Listen** under an answer | The deployment cannot speak | Same. Voice controls appear only when the deployment behind them can do the work. | +| `You’ve reached today’s limit for this model` | the daily message allowance is used up | wait for the reset named on the banner, or see [Plans and quotas](/getting-started/plans) | +| `You’ve reached this month’s limit for this model` | the monthly allowance is used up | same; the banner says when it resets | +| `Resets on its own.` | the reset time could not be named | retry later | +| A banner offering another model that is still available | one model is capped, another is not | take the offer, or start a new chat on the other model | +| `You have used today's messages` | the plan-limit detail behind a message cap | see [quota_exceeded](/problems/quota_exceeded) | +| `You have used today's document exports` | the plan-limit detail behind an export cap | wait for tomorrow; drafting an outline never counts | +| A **Sign in** action on a refusal | the thing you asked for needs an account | sign in; see [Accounts and sign-in](/getting-started/accounts) | +| An **Upgrade** action on a refusal | your plan does not include it | see [Plans and quotas](/getting-started/plans) and [entitlement_required](/problems/entitlement_required) | -See [Voice](/chat/voice). +Messages are charged against a daily and a monthly window at once, and the first one to run out is the one that stops you. Thinking is not metered on any plan. -## Quotas and access +## Documents, decks and exports -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| **Sign in to continue** above the composer | The guest allowance for today or this month is used up | Sign in to continue on Free, or wait for the reset. | -| [`quota_exceeded`](/problems/quota_exceeded) | A daily or monthly window is exhausted | The error carries when it resets. See [Plans and quotas](/getting-started/plans). | -| [`entitlement_required`](/problems/entitlement_required) | The plan does not include that capability at all | Compare plans under **Settings → Plan & billing**. | -| [`rate_limited`](/problems/rate_limited) | Too many requests in a short burst | Pause, then retry. | -| Projects, Library, or Memory are missing | You are a guest | Those need a signed-in account. See [Accounts](/getting-started/accounts). | -| A connected app cannot be used in Chat | The connection is enabled for Bot only | **Customize → Connectors** → enable it for **Cortex Chat**. See [Tools and connectors](/chat/tools). | -| No **Connect** control for an app | That connection is not available on this deployment, or you are a guest | Sign in; if it is still missing, it is not offered here. | +| `The document could not be opened.` | the canvas did not load | close and reopen the rail; see [Chat canvases](/chat/canvases) | +| `The document could not be saved.` | the last canvas save failed | copy the text out before retrying | +| `The deck could not be created` | the answer's deck export failed at the create step | retry; a failed write returns your export | +| `The deck could not be exported.` | the thread's deck export failed | use **Try again** | +| `The document writer is not available on this deployment.` | files cannot be typeset here | nothing to configure; the export is not charged | +| `Deck export is not available yet.` | the deck flow on a research report is not ready | retry later | +| `The outline could not be drafted.` | Cortex could not draft slides from this material | ask for a summary first, then export that | +| `The file could not be saved.` | saving an export to a connected drive failed | download the file instead; drive saving is not available in this wave | + +See [Export documents](/chat/document-export) for the whole flow and its allowances. + +## Searching + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Search could not run.` | the search request failed | try again | +| `No matches for` followed by your query | nothing matched in chat search | search matches conversation **titles** only, so try a word from the title | +| `No matches in this conversation.` | the in-conversation search found nothing | the hint says it: `Try a shorter word, or a term from the answer rather than the question.` | +| `No messages to search yet.` | the conversation is empty | ask something first | + +Chat search covers titles, Library and skills, eight results per group, and an empty query lists your recent chats. Its footer states the split with Code: `↑↓ to move · ↵ jump · Chat only · Code has its own palette`. + +## Organising a chat + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Chat titles cannot be renamed yet — this app has no route for it.` | renaming a chat is not available | a chat is named automatically from its first message; the title is never in the link | +| `You have 20 pinned chats and projects. Unpin one before pinning another.` | the pin cap is 20, shared between chats and projects | unpin something first | +| `A Temporary chat cannot be pinned or moved to a project.` | temporary chats cannot be filed | copy what you need into a normal chat | +| `Temporary is chosen when a chat starts.` | you cannot switch temporary on or off later | start a new temporary chat | +| `The chat could not be archived` | the archive did not stick | retry from the sidebar row | +| `The chat could not be deleted` | the delete failed | retry; deleting is permanent once it succeeds | +| `The chat could not be moved` | filing the chat failed | it adds `Please try again.` | +| `Could not load your projects` | the project list did not load | reopen the move dialog; `No projects yet` means you have none | +| `The note could not be saved` | saving a selection to Library failed | retry; the message adds `Please try again.` | +| `The plan could not be created` | the plan dialog failed | retry from **Start a plan** | + +Archiving takes a chat out of Recents and offers `Undo` in its toast. There is no separate view that lists archived chats afterwards, so treat archiving as hiding a chat from Recents rather than filing it somewhere you can browse. + +## Voice + +| What you see | What it means | What to do | +| --- | --- | --- | +| No microphone in the composer | this deployment cannot transcribe speech | nothing to configure; type instead | +| No **Listen** under an answer | this deployment cannot read answers aloud | same | +| `Voice is not available on this deployment.` | a live voice conversation is not reachable here | use dictation and read-aloud where they appear; see [Voice](/chat/voice) | + +## Sharing and copying + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Sharing is not on this deployment` | conversation sharing does not exist yet | export a file or copy the text; see [Sharing and teams](/chat/sharing) | +| `Sharing is not available for this message yet.` | a link to that message could not be built | copy the message text instead | +| `Copy failed` | the clipboard write was refused | check your browser's clipboard permission, then retry | +| `The link could not be copied.` | the same, for a message link | retry | ## Still stuck -Keep the `request_id` from the error, the time, and the surface you were on. Check [status.cortex.foundation](https://status.cortex.foundation) if Chat is failing alongside other products — see [System status](/status). Full error semantics: [Problem catalog](/problems). +Keep the request id shown on the error card, the time, and what you were doing. Then: + +- Look the code up in the [Problem catalog](/problems) or in [Errors](/reference/errors). +- Check [status.cortex.foundation](https://status.cortex.foundation) if other products are failing too, and see [System status](/reference/status). +- If it looks like a defect, follow [Report a bug](/getting-started/report-a-bug). ## Related -- [How Chat works](/chat/how-it-works) — the tool loop and its round budget. -- [Streaming](/chat/streaming) — what a dropped connection does and does not lose. -- [Troubleshooting](/getting-started/troubleshooting) — the same guidance across all products. +- [How Chat works](/chat/how-it-works) for the turn loop and its budgets. +- [Streaming and reconnects](/chat/streaming) for what a dropped connection does and does not lose. +- [Plans and quotas](/getting-started/plans) for every allowance behind a limit message. +- [Problem catalog](/problems) for the full list of error codes. +- [Troubleshooting](/getting-started/troubleshooting) for the same guidance across all products. diff --git a/chat/voice.mdx b/chat/voice.mdx index a851967..f60ff3c 100644 --- a/chat/voice.mdx +++ b/chat/voice.mdx @@ -1,42 +1,98 @@ --- title: "Voice" -description: "Dictate with the mic and hear an answer with Listen. Both controls appear only when the deployment can transcribe or speak." -keywords: ["dictation", "speech", "listen", "microphone", "text to speech"] +description: "Dictate a message with the microphone and hear an answer read back with Listen, including what each control sends and when it is missing" +icon: "microphone" --- -Chat has two voice controls: a **mic** in the composer for dictation, and **Listen** under each answer to hear it read aloud. Each appears only when the deployment behind it can actually do the work. +Cortex Chat has two voice controls, and they are independent of each other. **Voice input** in the composer turns speech into text you can edit before sending. **Listen** under a finished answer reads that answer aloud. Both are Chat controls: Cortex Code, Cortex Bot and Cortex Design have no equivalent. - - A Chat reply with a syntax-highlighted Python code block and the Copy and Listen controls beneath it - +This page covers how each one behaves, what it does and does not send on your behalf, the limits that apply, and what it means when one of the controls is not there at all. -## The controls +## The two controls -| Control | Where | Appears when | What it does | -| --- | --- | --- | --- | -| **Mic** | In the composer | The deployment can transcribe | Turns speech into text in the composer; you still press **Enter** to send | -| **Listen** | Under an answer | The deployment can speak | Reads the answer aloud | +| Control | Where it is | What it does | +| --- | --- | --- | +| **Voice input** | In the composer | Records a short clip, transcribes it, and puts the text in the composer for you to edit | +| **Listen** | On a finished answer | Reads the answer aloud. The tooltip is **Read aloud** | -If a control is missing, that capability is switched off for this deployment. There is nothing to configure on your side, and it is not a broken button. +Each control appears only where the capability behind it is configured. Cortex asks once whether speech-to-text and text-to-speech are available and draws the controls accordingly, so a control you can see is a control that works. Nothing is drawn greyed out, and you will not meet a button that fails when you click it. -Dictation fills the composer; it does not send the turn. Read what landed there, fix a word if the transcript misheard it, and press **Enter** yourself. **Listen** appears under a finished reply, alongside **Copy** and the feedback controls — see [Streaming](/chat/streaming) for the phases that come before it. +## Dictate a message -## Where voice lives + + + Click **Voice input** in the composer. If the button is not there, dictation is not configured where you are running Cortex. + + + The button becomes **Stop recording** while the clip is being captured. + + + Stop recording. The composer shows **Transcribing…**, then drops the transcript into the message box as ordinary editable text. + + + Correct anything that was misheard and send the message yourself. + + -| Surface | Dictation | Spoken answers | -| --- | --- | --- | -| Cortex Chat (web) | Yes, when the deployment can transcribe | Yes, when it can speak | -| Code, Bot, Design | No — voice is a Chat control | No | -| CLI | No. The terminal has no mic and no playback — see [The TUI](/cli/tui) | + +Dictation never sends for you. The transcript lands in the composer and stays there until you press send, which is what makes it safe to dictate a long message and then edit it. + + +Once the clip has been turned into text, the recording itself is not kept. The text in the composer is what survives, and from that point it is an ordinary message like any other. + +## Listen to an answer + + + + On a finished answer, choose **Listen**. If there is no such button, read-aloud is not configured where you are running Cortex. + + + The button shows **Loading…** while the audio is prepared, then playback starts and the button becomes **Stop**. + + + **Stop** ends playback. Starting playback on a second answer stops the first one, so only one answer is ever read aloud at a time. + + + +Read-aloud works on the answer as it stands when you press the button, which is why **Listen** belongs to a finished answer rather than one still being written. See [Streaming and reconnects](/chat/streaming) for the phases that come before it. + +## Limits + +| Limit | Value | +| --- | --- | +| A single dictated clip | Up to 25 MiB | +| Text sent for read-aloud in one request | Up to 3,000 characters | +| Read-aloud voices | English | + +For everything else, a dictated message counts against your message allowance exactly like a typed one, because by the time it is sent it is a typed one. See [Plans and quotas](/getting-started/plans). + +## A live voice conversation is not available yet + + +There is no live, two-way voice mode in Chat today. Talking to Cortex and hearing it answer in the same session is not available, and any path that leads there ends on **Voice is not available on this deployment.** Dictation and **Listen** are the two voice features that work. + + +Use them together if you want something close to a spoken exchange: dictate the question with **Voice input**, send it, then press **Listen** on the answer. The difference is that each half is a deliberate action rather than an open microphone, and nothing is recorded between them. + +## When a control is missing + +A missing mic or a missing **Listen** button is not a fault on your side, and there is nothing in your own settings to switch on. Each half is configured where Cortex is running, and either can be available without the other. -Chat's voice controls are the only place these capabilities appear. A session in Code, a bot's conversation, and a terminal session have no equivalent. +| What you see | What it means | +| --- | --- | +| No **Voice input** in the composer | Dictation is not configured here | +| No **Listen** on answers | Read-aloud is not configured here | +| **Speech-to-text is not configured.** | Dictation was requested but is not set up | +| **Text-to-speech is not configured.** | Read-aloud was requested but is not set up | +| **Text-to-speech is temporarily unavailable.** | A passing failure. Try the same answer again shortly | -## Language +If the mic button is present but your browser never starts recording, the block is usually the browser's own microphone permission for the site rather than Cortex. Allow the microphone in your browser's site settings and try again. -English is the source of truth for spoken and written copy. The interface can be localized under **Settings → General → Language**; model prompts stay in English. See [Settings](/getting-started/settings). +Interface language is a separate matter from the voice controls and is covered in [Language](/getting-started/language). ## Related -- [Streaming](/chat/streaming) — answers arrive as text before you can listen to them. -- [Chat troubleshooting](/chat/troubleshooting) — a missing mic or Listen control. -- [Troubleshooting](/getting-started/troubleshooting) — what missing controls mean. +- [Streaming and reconnects](/chat/streaming) - an answer has to finish before it can be read aloud. +- [Conversations](/chat/conversations) - the rest of the controls on an answer. +- [Chat troubleshooting](/chat/troubleshooting) - a missing mic or a silent **Listen** button. +- [Getting started troubleshooting](/getting-started/troubleshooting) - what a missing control means in general. diff --git a/cli/agents.mdx b/cli/agents.mdx new file mode 100644 index 0000000..7b166cc --- /dev/null +++ b/cli/agents.mdx @@ -0,0 +1,159 @@ +--- +title: "Agents and subagents" +description: "Named configurations for how the CLI behaves, the tool categories they grant, and the subagents the main agent delegates to" +icon: "sitemap" +--- + +An agent is a named configuration for how Cortex should behave: which model, how much reasoning, and which tools it is allowed to touch. Cortex ships a few and you can add your own. A **subagent** is an agent the main one delegates to, so a long job can be split into pieces that report back. + +This page covers the agents the CLI ships with, the commands for listing and creating them, the fields in an agent file, the six tool categories, where agent files are found, how to select one for a run, and what delegation to a subagent does and does not allow. + +## The agents that ship with the CLI + +| Agent | Kind | Behaviour | +| --- | --- | --- | +| `build` | Primary | Full access. The default working agent | +| `plan` | Primary | Read-only. Investigates and proposes without changing anything | +| `explore` | Subagent | Read-only investigation, capped at 15 steps | +| `general` | Subagent | General-purpose worker. Cannot delegate further | +| `research` | Subagent | Read-only research | +| `title` | Primary | Names sessions. Uses the small model | +| `summary` | Primary | Summarises sessions. Uses the small model | + +`title` and `summary` are internal housekeeping; you will not normally select them by hand. + + +An agent is not a mode. The `plan` agent is a configuration that happens to be read-only, while Plan mode is a lock on the whole session that holds whichever agent you are using. See [Modes and permissions](/cli/modes-and-permissions). + + +## Manage agents + +```bash +cortex agent list # everything available +cortex agent list --primary # only primary agents +cortex agent list --subagents # only subagents +cortex agent list --json +cortex agent show +cortex agent create # interactive +cortex agent create --generate "reviews Rust for concurrency bugs" +cortex agent edit # opens $EDITOR +cortex agent copy +cortex agent export -o agent.md +cortex agent install +cortex agent remove +``` + +Inside a session, `/agents` lists and manages them and `/delegates` covers subagents. `cortex agent install` pulls a definition from a registry; run `cortex agent install --help` on your build to see which sources it accepts. + +## Write an agent + +An agent is a markdown file with YAML frontmatter. The body is the agent's system prompt. + +```markdown +--- +name: reviewer +description: Reviews a change for correctness and concurrency bugs +model: inherit +reasoning_effort: high +tools: read-only +max_steps: 40 +--- + +You review code. Read the change, then report the problems you are confident +about, most serious first. Do not edit files and do not run commands. +``` + +| Field | Type | Notes | +| --- | --- | --- | +| `name` | string | How the agent is selected | +| `description` | string | Shown in `cortex agent list` | +| `model` | string | A model id, or `inherit` to use the session's model. Default `inherit` | +| `reasoning_effort` | `low` / `medium` / `high` | How hard the model thinks | +| `tools` | category or list | A category name, or an explicit list of tool names | +| `temperature` | number | | +| `max_steps` | integer | Cap on tool-calling steps | +| `color` | string | Colour used in the session view | +| `hidden` | bool | Hide from the default listing | +| `omit_instructions` | list | Instruction documents this agent skips | + +### The six tool categories + +| Category | Grants | +| --- | --- | +| `read-only` | `Read`, `LS`, `Grep`, `Glob` | +| `edit` | `Create`, `Edit`, `ApplyPatch` | +| `execute` | `Execute` | +| `web` | `WebSearch`, `FetchUrl` | +| `mcp` | Tools from connected MCP servers | +| `all` | The full built-in set | + +`tools` takes either a category name or an explicit list of tool names, and an explicit list is exact. The names are case-sensitive: see [Tools the agent uses](/cli/tools). + +### Where agent files are found + +Searched in this order, and the first definition of a name wins: + +1. `/.agents/*.md` +2. `/.agent/*.md` +3. `/.cortex/agents/*.md` +4. `~/.cortex/agents/*.md` +5. `~/.config/cortex/agents/*.md` + +Project agents therefore override personal ones, which is what you want when a repository has house rules. + +## Select an agent + +```bash +cortex run --agent reviewer "review the last commit" +cortex --config current_agent=reviewer +``` + +```toml +# config.toml +current_agent = "reviewer" +``` + +In a prompt, `@name` mentions an agent directly: + +``` +> @reviewer take a look at src/auth before I push this +``` + + +`@` is also the file-reference sigil in the composer, so `@src/main.rs` and `@reviewer` are typed the same way. When a name could be read either way, pass `--agent` or set `current_agent` instead of relying on the mention. + + +## Instruction documents an agent skips + +Agents read the repository's instruction documents. The chain is your home directory, then the repository root `AGENTS.md`, then any `AGENTS.md` between the root and your working directory. `cortex init` writes one for a repository that does not have it yet. + +`omit_instructions` lets an agent skip part of that chain for one run: + +| Scope | Documents | +| --- | --- | +| `user` | The `AGENTS.md` in your Cortex home directory | +| `project` | The repository-root `AGENTS.md` | +| `local` | `AGENTS.md` files between the repository root and the working directory | +| `managed` | Organization policy. Never omitted | + +Omission is opt-in and applies to that run only. A skipped document is never opened, so it cannot reach the prompt by another path. Organization-managed policy always loads: a request that names `managed` is accepted, recorded, and ignored, and the same is true when the main agent passes `omit_instructions` to the `Task` tool. An unknown scope name is an error rather than a silent no-op, so a typo cannot omit the wrong documents. Every omission is recorded in the audit journal under your Cortex home directory, described in [Permission policy](/cli/policy). + +## Delegation and subagents + +Subagents are agents the main agent delegates to, through the `Task` tool. A task runs in one of three roles, `explore`, `plan` or `worker`, and reports back when it finishes. + +Delegated work is constrained: a child task cannot spawn its own children, ask you questions directly, or message you. Everything flows back through the parent. `/tasks` shows what is running in the background. + +Three overlapping lists are worth keeping straight: + +- **Three roles** a task can run in: `explore`, `plan`, `worker`. +- **Eight built-in subagent types**: `code`, `research`, `refactor`, `test`, `documentation`, `security`, `architect` and `reviewer`, plus any custom agent you define. +- **Seven built-in agents**, in the table at the top of this page. + +## Related + +- [Tools the agent uses](/cli/tools) +- [Skills in the CLI](/cli/skills) +- [Modes and permissions](/cli/modes-and-permissions) +- [Permission policy](/cli/policy) +- [Headless and one-shot runs](/cli/headless) diff --git a/cli/ci.mdx b/cli/ci.mdx new file mode 100644 index 0000000..6485577 --- /dev/null +++ b/cli/ci.mdx @@ -0,0 +1,183 @@ +--- +title: "CI cookbook" +description: "Run the CLI in a pipeline: pick a command, pass the secret through the environment, set the autonomy level, and fail the job on the exit code" +icon: "code-merge" +--- + +A continuous integration job is the least forgiving place to run an agent. Nobody is watching, nothing can be approved interactively, and a run that hangs costs you a runner. This page is the set of recipes that work, with the details that usually go wrong called out: how the job authenticates, how much authority the run gets, what to parse, and how the job should fail. + +It assumes you have read [Headless and one-shot runs](/cli/headless), which describes the two commands themselves. Here we only cover what changes when the pipeline is driving them. + +## Pick the right command + +| You want | Use | +| --- | --- | +| A single answer, streamed, human-readable | `cortex run` | +| A machine-readable result document | `cortex run --format json` | +| Multi-turn, controllable, scriptable | `cortex exec` with a streaming input format | +| Strict autonomy control | `cortex exec --auto read-only`, or a higher level, deliberately | + +Most jobs want the second or the fourth row. Reach for streaming input only when the pipeline really does need to send more than one message and react in between. + +## Authenticate the job + +Credentials resolve in a fixed order: `CORTEX_AUTH_TOKEN` first, then `CORTEX_API_KEY`, and only then the credential `cortex login` stored. A CI runner has no credential store and no browser, so `cortex login` cannot complete its interactive flow there. An environment variable is the only path that works, and because it is checked first it also wins on a machine that does have a stored sign-in. + +Set the secret on the job or step, from your provider's secret store, and never bake a token into an image: + +```bash +# The variable is enough. No cortex login step is needed. +export CORTEX_API_KEY="$CI_SECRET" +cortex run --format json "summarise the changes on this branch" +``` + +If you would rather store the credential in the runner's own auth file, read it from standard input so it never reaches shell history or a process listing: + +```bash +printf '%s' "$CORTEX_API_KEY" | cortex login --with-api-key +``` + +See [Sign in to the CLI](/cli/sign-in) for the full set of sign-in paths. + +## Install the CLI in the job + +Install from the release host as a job step, then check the version so a broken install fails early rather than mid-run: + +```bash +curl -fsSL https://software.cortex.foundation/install.sh | sh +cortex --version +``` + +On Windows runners, use the PowerShell installer from the same host. Do not pin a version in your pipeline unless you have a reason to: take it from the release channel. + +## GitHub Actions + +```yaml +name: Cortex review +on: [pull_request] + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install the CLI + run: curl -fsSL https://software.cortex.foundation/install.sh | sh + - name: Review the diff + env: + CORTEX_API_KEY: ${{ secrets.CORTEX_API_KEY }} + run: | + cortex exec --auto read-only --git-diff \ + --timeout 600 --max-turns 20 \ + -o json "Review this diff for bugs, security issues and missing tests" > review.json + - name: Show the result + run: jq -r '.' review.json +``` + +Four details carry this recipe: + +- **`fetch-depth: 0`.** The default checkout is shallow, and an agent cannot diff against a base branch it does not have. This is the single most common cause of "the agent cannot see my changes". +- **`env:` at the step level**, so the secret is exposed to the one step that needs it. +- **A JSON output format**, because the default text shape is not a contract and will break your parser one day. +- **`--timeout` and `--max-turns` on every invocation.** Defaults exist, 600 seconds and 100 turns, but a pipeline should state its own. + +`cortex github install` scaffolds workflows for pull-request review and issue automation if you would rather not maintain the YAML yourself. See [GitHub](/code/github). + +## GitLab CI + +```yaml +code-review: + script: + - curl -fsSL https://software.cortex.foundation/install.sh | sh + - cortex exec --auto read-only -o json "Review the code changes" > review.json + artifacts: + paths: [review.json] +``` + +Mark the credential variable as masked in the project's settings so it does not appear in job logs. + +## A shell script + +The same shape works in any runner, and it is worth keeping the early exit: a job that had nothing to review should pass, not spend a turn. + +```bash +#!/usr/bin/env bash +set -euo pipefail + +if git diff --quiet; then + echo "No changes to review" + exit 0 +fi + +cortex exec --auto read-only --git-diff \ + --timeout 300 --max-turns 20 \ + -o json "Review these changes for issues" > review.json +``` + +## Decide the autonomy before the run + +In CI there is nobody to answer an approval prompt, so what the run may do has to be settled by policy in advance. Three controls do that, and they compose: + +- `--auto`, the level for this run, `read-only` by default. +- `.cortex/permissions.toml`, committed to the repository, pinning individual rules. First matching rule wins, and deny beats allow. +- The `[permission]` table in configuration, which can set a capability to `allow`, `ask` or `deny`. A project `.cortex/config.toml` carries these and beats the user's own configuration, which makes it the right place to pin what CI may do for a given repository. + + +When a run hits a permission refusal, grant the specific capability through the `[permission]` table, or raise `--auto` to `high` if the job genuinely needs it. `--skip-permissions-unsafe` is not the lever: `cortex exec` refuses it outright, with `--skip-permissions-unsafe is not supported by the Code service contract. No turn was submitted.` + + +A hook is not consent. No hook can approve a tool call on your behalf, and adding hooks does not raise what a run is permitted to do. Hooks are also not the lever for stopping something in CI: they belong to a plugin and do not fire around the tool calls a run makes. Pin what a job may do with the `[permission]` table above. See [Hooks](/cli/hooks) and [Permission policy](/cli/policy). + +## Restrict network egress + +Network egress is blocked by default in a headless run. When you want a specific, reviewable restriction for a repository, commit a `.cortex/sandbox.toml` to it: it restricts egress for runs in that repository, and because it is in the repository, every CI run inherits the same rules without anyone remembering to pass a flag. + +## Fail the job on the exit code + +Branch on the exit status, not on prose in the output: + +```bash +if cortex exec --auto read-only --timeout 300 -o json "Check for regressions" > out.json; then + echo "run completed" +else + echo "run failed, interrupted or truncated" + exit 1 +fi +``` + +Exit `0` means the task completed. Any non-zero exit means the run failed, was interrupted, was truncated, or the coding service was unreachable. That is the contract, so do not wrap a failing run in `|| true`. The JSON result document tells the cases apart if the job needs to know which one it was. + +Two small things while you are here. `--dry-run` belongs to `cortex run` rather than `cortex exec`, and it previews what would be sent, with estimated token counts, without executing: the cheap way to test a pipeline change. And `-n`/`--notification`, also on `cortex run`, raises a desktop notification, which is pointless on a runner. + +## Driving a multi-turn run + +For a pipeline that sends more than one message, `cortex exec` accepts a streaming input format: one JSON object per line on standard input, plus two control messages. + +```json +{"control":"interrupt"} +{"control":"shutdown"} +``` + +The value for that input format is `stream-jsonl`: every non-empty line is the next turn, the stream needs no envelope or ids, and the connection stays open after a turn completes. `--input-format stream-jsonrpc` is the JSON-RPC variant instead, for a pipeline that wants request ids and matching responses. + +## Troubleshooting + +| Symptom | What to do | +| --- | --- | +| Authentication fails | Check the variable name, and that the secret is actually exposed to that job or step | +| Output is not valid JSON | You are on the default text format. Add `--format json` or `-o json` | +| The run never ends | Set `--timeout` and `--max-turns` | +| The agent cannot see the branch you want to diff | Shallow clone. Set `fetch-depth: 0` or the equivalent | +| Permission refusals | Grant the specific capability through the `[permission]` table, or raise `--auto` to `high`, rather than trying to disable checks | + +If the run reports that the coding service is temporarily unavailable, that message is the whole story: retry the job. See [CLI troubleshooting](/cli/troubleshooting). + +## Related + +- [Headless and one-shot runs](/cli/headless), the two commands and their flags +- [Permission policy](/cli/policy), rules that decide an unattended run's authority +- [Sign in to the CLI](/cli/sign-in), credentials for a runner +- [Cloud, This PC, and SSH](/cli/hosts), where a CI run executes its tools +- [Cortex Security](/security), a review that runs on pull requests without a pipeline of your own diff --git a/cli/configuration.mdx b/cli/configuration.mdx index de063a4..5ff709a 100644 --- a/cli/configuration.mdx +++ b/cli/configuration.mdx @@ -1,64 +1,71 @@ --- title: "Configuration" -description: "config.toml keys, profiles, precedence, the environment variables the CLI reads, where data lives on disk, and how to select the Cloud, This PC, or SSH host." -keywords: ["config.toml", "settings", "environment variables", "profiles"] +description: "How Cortex CLI reads config.toml, the keys you can set, named profiles, and which layer wins when two files disagree." +icon: "gear" --- -Cortex reads a **global** config file, an optional **project** config file, and any overrides you pass on the command line — in that order, later sources winning. Environment variables sit between the files and the flags. +Cortex CLI keeps its settings in a TOML file. There is one for you, an optional one per repository, and a set of overrides you can pass on the command line. Between them they decide which model a session starts on, how much the agent may do without asking, how the terminal app looks, and how long a command may run before it is killed. -## Where the files live +This page covers where the files live, the order in which they are merged, the keys you can set in each section, and how named profiles let you keep several setups side by side. Permission and sandbox rules have their own page, and so do the environment variables that sit above the files in precedence. + +## Where the config file lives | Scope | Location | | --- | --- | -| Global | `~/.cortex/config.toml` — or `CORTEX_CONFIG_DIR`, `CORTEX_HOME`, or `CORTEX_CONFIG` if set. TOML, JSON, and JSONC are accepted by extension. | -| Project | The first of `.cortex/config.toml`, `.cortex/config.json`, `.cortex/config.jsonc`, `cortex.toml`, `cortex.json`, `cortex.jsonc`, walking up from the working directory to the project or git root | -| Command line | `-c key=value` / `--config key=value`, repeatable. Values parse as TOML scalars. | +| Yours, macOS and Linux | `~/.cortex/config.toml` | +| Yours, Windows | `%USERPROFILE%\.cortex\config.toml` | +| Project | `.cortex/config.toml` in the repository root | + +The Cortex home directory is resolved in this order: `CORTEX_CONFIG_DIR`, then `CORTEX_HOME`, then `~/.cortex`. `CORTEX_CONFIG` overrides the config file path outright, wherever the home directory ends up. -Commit the project file when the settings belong to the repository rather than to you. +Inside a project, Cortex looks for `.cortex/config.toml`, then `.cortex/config.json`, then `.cortex/config.jsonc`, then `cortex.toml`, `cortex.json` and `cortex.jsonc`. The first one it finds is the project config. Commit the project file when the settings belong to the repository rather than to you. ## Precedence -From strongest to weakest: +Five layers, weakest first. A later layer overrides a key set by an earlier one. + +1. Built-in defaults +2. Your own config, `~/.cortex/config.toml` +3. The profile selected with `-p` / `--profile`, or by `profile = ""` +4. The project config, `.cortex/config.toml` +5. The command line: `-c` / `--config KEY=VALUE`, repeatable, then the dedicated flags + +Environment variables sit between config files and command-line flags in precedence: a flag beats a variable, a variable beats a config file. See [Environment variables](/cli/environment-variables) for the full list. -1. `-c` / `--config` overrides and other command-line flags -2. Environment variables -3. Project config file -4. Global config file -5. Built-in defaults + +A project `.cortex/config.toml` beats your own `~/.cortex/config.toml`. Cloning a repository can therefore change your model, your sandbox mode and your approval policy without you touching anything. Run `cortex config` in a new clone to see the values that are actually in effect. + ## Inspect and edit ```bash -cortex config # the resolved configuration -cortex config --json -cortex config --edit -cortex config get -cortex config set -cortex config unset - -cortex debug config --env # which environment variables influence the result -cortex debug config --diff # what differs from the defaults +cortex config # the effective configuration +cortex config get +cortex config set +cortex config unset +cortex config --json # the same, machine-readable +cortex config --edit # edit it interactively +cortex debug config # what is in effect, and which files it came from +cortex debug doctor # check configuration, storage and required tools ``` -`/config` and `/reload-config` do the reading from inside the TUI. - - - Cortex CLI /config tree view of the effective configuration - +From inside the terminal app, `/config` opens the same file and `/reload-config` re-reads configuration from disk. ## Keys ### Model -| Key | Notes | -| --- | --- | -| `model` | Default model | -| `model_reasoning_effort` | `low` · `medium` · `high` | -| `model_reasoning_summary` | `none` · `brief` · `detailed` · `auto` | -| `model_context_window` | Override the assumed context window | -| `model_auto_compact_token_limit` | When to auto-compact the conversation | -| `model_aliases` | Map your own short names to model ids | -| `small_model` | Used for cheap background work such as titles and summaries | +| Key | Type | Notes | +| --- | --- | --- | +| `model` | string | Default model | +| `model_provider` | string | Provider id | +| `model_context_window` | integer | Override the assumed context window | +| `model_auto_compact_token_limit` | integer | When to auto-compact the conversation | +| `model_reasoning_effort` | `low`, `medium`, `high` | Reasoning effort | +| `model_reasoning_summary` | `none`, `brief`, `detailed`, `auto` | How much reasoning is summarised | +| `model_aliases` | table | Map your own short names to model ids | +| `small_model` | string | Model used for cheap background work such as titles and summaries | +| `providers` | table | Custom provider definitions | ### Permissions and sandboxing @@ -66,74 +73,83 @@ cortex debug config --diff # what differs from the defaults | --- | --- | --- | | `approval_policy` | `untrusted`, `on-failure`, `on-request`, `never` | When to ask before running a tool. `on-request` is the default. | | `sandbox_mode` | `read-only`, `workspace-write`, `danger-full-access` | What the sandbox permits. `workspace-write` is the default. | -| `trusted_directories` | array of paths | Directories that do not prompt on entry | +| `trusted_directories` | array of paths | Read from both layers and merged, but nothing in this build consults the merged list. Do not rely on it to skip a prompt. | -```toml -sandbox_mode = "workspace-write" +`[sandbox_workspace_write]` refines `workspace-write` with `writable_roots`, `network_access`, `exclude_tmpdir_env_var` and `exclude_slash_tmp`. The `[permission]` table sets per-capability and per-command policy. Both are documented on [Permission policy](/cli/policy). -[sandbox_workspace_write] -writable_roots = ["/tmp/scratch"] -network_access = false -``` +### Behaviour -The `permission` table sets per-capability policy — see [Modes and permissions](/cli/modes-and-permissions#the-permission-table). +| Key | Type | Meaning | +| --- | --- | --- | +| `instructions` | string | Extra instructions prepended to every session | +| `current_agent` | string | Agent used by default | +| `hide_agent_reasoning` | bool | Hide reasoning output | +| `show_raw_agent_reasoning` | bool | Show reasoning verbatim | +| `check_for_update_on_startup` | bool | Look for a new release on launch | +| `disable_paste_burst` | bool | Turn off paste-burst detection in the composer | -### Behaviour +### History -| Key | Meaning | -| --- | --- | -| `instructions` | Extra instructions prepended to every session | -| `current_agent` | The agent used by default | -| `hide_agent_reasoning` / `show_raw_agent_reasoning` | Reasoning display | -| `check_for_update_on_startup` | Look for a new release on launch | -| `disable_paste_burst` | Turn off paste-burst detection in the composer | +```toml +[history] +persistence = "save-all" # or "none" +max_bytes = 10000000 +``` -### TUI +### Terminal app ```toml [tui] animations = true notifications = true -alternate_screen = true # false stays inline in the host terminal +# Enter the alternate screen buffer. Set false to stay inline in the host +# terminal. Equivalent flag: --no-alternate-screen +alternate_screen = true [tui.theme] -name = "dark" # dark, light, ocean_dark, monokai +name = "dark" # dark, light, ocean_dark, monokai ``` -The same options are interactive under `/settings` (or **F2**) — Appearance, Mouse, Behavior, AI, Git, Cloud, Privacy — with a search box at the top. +The theme ids stay lowercase in config even though the picker shows friendlier names. See [Themes](/cli/themes). - - Cortex CLI settings modal open on the Appearance section - - -### History and execution +### Execution ```toml -[history] -persistence = "save-all" # or "none" -max_bytes = 10000000 - [execution] max_agent_threads = 4 max_tool_threads = 8 command_timeout_seconds = 120 http_timeout_seconds = 60 +max_retries = 3 +retry_delay_ms = 1000 streaming = true +max_file_size_bytes = 10485760 +max_batch_files = 100 +verbose = false ``` -Each `execution` key has a flag: `--max-agent-threads`, `--max-tool-threads`, `--command-timeout`, `--http-timeout`, `--no-streaming`. +Each of these has a flag: `--max-agent-threads`, `--max-tool-threads`, `--command-timeout`, `--http-timeout`, `--no-streaming`. -### Extensions +### Plugins -| Key | Points at | -| --- | --- | -| `mcp_servers` | [MCP servers](/cli/extend#mcp-servers) | -| `plugins`, `plugin_dirs`, `plugin_settings` | [Plugins](/cli/extend#plugins) | -| `commands` | Custom slash commands | +Plugins are configured in the same file: -### Profiles +```toml +[[plugins]] +name = "my-plugin" +path = "~/.cortex/plugins/my-plugin" +enabled = true +priority = 0 +granted_permissions = ["read_files", "network"] + +[plugins.config] +api_key = "your-api-key" +max_items = 20 +``` + +## Profiles -A profile is a named bundle you select with `-p` / `--profile`: +A profile is a named block that overrides top-level keys. Anything you can set at the top level you can set in a profile. ```toml [profiles.review] @@ -142,99 +158,17 @@ approval_policy = "never" sandbox_mode = "read-only" ``` -```bash -cortex --profile review "review the last three commits" -``` - -## Environment variables - -Values are never documented here — keep secrets in your keyring or CI secret store. - -### Locations - -| Variable | Effect | -| --- | --- | -| `CORTEX_HOME` | Root for config and data. Default `~/.cortex`. | -| `CORTEX_CONFIG_DIR` | Config directory, taking priority over `CORTEX_HOME` | -| `CORTEX_CONFIG` | Path to a specific config file | -| `CORTEX_DATA_DIR` · `CORTEX_CACHE_DIR` | Data and cache directories | - -### Account - -| Variable | Effect | -| --- | --- | -| `CORTEX_API_KEY` | API key for headless and CI use | -| `CORTEX_AUTH_TOKEN` | Session or bearer token | -| `CORTEX_API_URL` | API base URL. Defaults to `https://api.cortex.foundation`. | - -Interactive use should prefer `cortex login`. See [Sign in](/cli/sign-in). - -### Host for Code - -The TUI and `cortex exec` create a **Cloud** Code session unless you select another host. - -| Variable | Effect | -| --- | --- | -| `CORTEX_COMPUTER` | Unset or `cloud` uses the Cloud. `this_pc` (aliases `this-pc`, `local`, `paired`, `connected`) or `ssh` selects those hosts. | -| `CORTEX_SSH_HOST` (alias `CORTEX_SSH_TARGET`) | SSH target; setting it selects SSH | - -This PC and SSH require an **already connected** Code session. Cortex will not create one on the fly and will not substitute the Cloud silently. See [Code on desktop](/code/desktop). - -### Model, logging, diagnostics - -| Variable | Effect | -| --- | --- | -| `CORTEX_MODEL` · `CORTEX_DEFAULT_MODEL` | Default model and fallback | -| `CORTEX_MAX_TOKENS` · `CORTEX_TEMPERATURE` | Response cap and sampling default | -| `CORTEX_LOG_LEVEL` | `error`, `warn`, `info`, `debug`, `trace` | -| `RUST_LOG` · `RUST_BACKTRACE` | Standard Rust logging controls | -| `NO_COLOR` | Disable colour; `--color never` sets it for child processes | -| `CORTEX_DIAGNOSTICS_DIR` | Where `--debug` writes bounded, content-free diagnostics | - -### Set for you, not by you - -Hook scripts and plugins can read `CORTEX_FILE`, `CORTEX_SESSION_ID`, `CORTEX_MESSAGE_ID`, and `CORTEX_PLUGIN_ARGS`. Cortex populates them for the processes it spawns. - -### Standard variables Cortex respects - -`EDITOR` / `VISUAL` for `cortex agent edit` and similar; `SHELL` for completions; `HTTPS_PROXY` / `HTTP_PROXY` for `cortex scrape`; `PATH`, `TERM`, `LANG`, `LC_ALL`, `USER` in `cortex debug system`. - -## Data locations - -```bash -cortex debug paths -``` - -```text -~/.cortex/ -├── config.toml Global configuration -├── sessions/ Session transcripts (and goal.json beside a goal) -├── code-sessions.json Workspace → Code session id -├── agents/ Personal agents -├── skills/ Personal skills -├── plugins/ Installed plugins -├── mcp/ MCP server state -├── snapshots/ Workspace snapshots -├── cache/ Model, response, and update caches; logs/ inside -├── feedback/ Queued feedback submissions -├── aliases.toml Command aliases -└── session_locks.json Sessions protected from cleanup -``` - -Inside a project: `AGENTS.md` (from `cortex init`), `.cortex/config.toml`, `.cortex/agents/`, `.cortex/skills/`, `.cortex/plugins/`, `.cortex/commands/`. `.agents/` and `.agent/` are also scanned. Project files take priority over personal ones with the same name. - -Some subsystems use the platform application directory — `~/.local/share/Cortex/` on Linux, `~/Library/Application Support/Cortex/` on macOS, `%APPDATA%\Cortex\` on Windows — and the platform cache directory. A legacy `~/.config/cortex` is still read so older installs keep working. - -**Credentials** live in the OS keyring, not in any of these directories. See [Sign in](/cli/sign-in). +Select it for one invocation with `-p review`, or set `profile = "review"` at the top level to make it your default. A profile sits below the project config, so a repository can still override it. -## Shell completions - -```bash -cortex completion bash --install # also zsh, fish, powershell, elvish -``` + +Nothing in the CLI documentation states whether Cortex prompts you before honouring a repository's `.cortex/config.toml`. Treat an unfamiliar repository's config as something to read before you run a session in it. + ## Related +- [Environment variables](/cli/environment-variables) +- [Data locations](/cli/data-locations) +- [Permission policy](/cli/policy) - [Modes and permissions](/cli/modes-and-permissions) -- [Extend](/cli/extend) — `mcp_servers`, agents, skills, hooks, plugins. -- [Troubleshooting](/cli/troubleshooting) +- [Themes](/cli/themes) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/data-locations.mdx b/cli/data-locations.mdx new file mode 100644 index 0000000..0fa797d --- /dev/null +++ b/cli/data-locations.mdx @@ -0,0 +1,110 @@ +--- +title: "Data locations" +description: "Where Cortex CLI keeps config, sessions, agents, skills, plugins, caches and logs on each platform, and how to reclaim the space." +icon: "folder-tree" +--- + +Cortex CLI keeps almost everything it needs in one directory, the Cortex home. Sessions, personal agents and skills, installed plugins, caches and logs all live under it, which makes the whole install easy to back up, move or delete. A few subsystems use the conventional per-platform application directory instead, and sign-in material deliberately lives outside the filesystem entirely. + +This page lists what Cortex writes and where, on macOS, Linux and Windows, and the commands that show you how much of it has accumulated and remove what you no longer need. It covers only the files on your own machine. + +## The Cortex home directory + +The root is resolved in this order: + +1. `CORTEX_CONFIG_DIR` +2. `CORTEX_HOME` +3. `~/.cortex` + +Under that root: + +| Path under the root | Contents | +| --- | --- | +| `config.toml` | Global configuration | +| `sessions/` | Session transcripts | +| `code-sessions.json` | Workspace to Code session id cache | +| `agents/` | Personal agents | +| `skills/` | Personal skills | +| `plugins/` | Installed plugins | +| `mcp/` | MCP server state | +| `snapshots/` | Workspace snapshots | +| `cache/` | Model, response and update caches | +| `cache/logs/` | Application logs | +| `auth/` | Sign-in bookkeeping. The credentials themselves live in the OS credential store, not here | +| `feedback/` | Queued feedback submissions | +| `aliases.toml` | Command aliases | +| `session_locks.json` | Sessions protected from cleanup | + +Two more appear only under some conditions. A `diagnostics/` directory exists once diagnostics are switched on, and `audit/events.jsonl` is written when a managed organization policy makes a fail-closed decision, as described on [Permission policy](/cli/policy). + +Individual directories can be moved with `CORTEX_DATA_DIR` and `CORTEX_CACHE_DIR`, so you can keep the config in your home directory and put the bulky parts on another volume. + +## Inside a project + +These are the files Cortex reads and writes inside a repository. They are ordinary files: commit the ones that belong to the project. + +| Path | Contents | +| --- | --- | +| `AGENTS.md` | Project instructions, created by `cortex init` | +| `.cortex/config.toml` | Project configuration | +| `.cortex/agents/` | Project agents | +| `.cortex/skills/` | Project skills | +| `.cortex/plugins/` | Project plugins | +| `.cortex/commands/` | Project slash commands | +| `.agents/`, `.agent/` | Alternative agent and skill locations that are also scanned | + +Project files take priority over personal ones with the same name. If a repository ships a skill called `deploy` and you have one of your own, the repository's wins inside that repository. + +## Platform directories + +Some subsystems use the conventional per-platform application directory rather than `~/.cortex`: + +| Platform | Path | +| --- | --- | +| Linux | `~/.local/share/Cortex/` | +| macOS | `~/Library/Application Support/Cortex/` | +| Windows | `%APPDATA%\Cortex\` | + +The maintenance commands also read the platform cache directory, `~/.cache/cortex/` on Linux, for logs and caches. Both of these honour `CORTEX_DATA_DIR` and `CORTEX_CACHE_DIR`. A legacy `~/.config/cortex` location is still read for configuration, agents and skills so that older installs keep working. + + +On Windows the split is worth knowing: configuration and data sit under `%APPDATA%\Cortex\`, while a 64-bit install puts the executable in `%LOCALAPPDATA%\Cortex\bin`. Add that folder to your user `PATH` yourself. The installer does not edit your profile or your `PATH`. + + +## Credentials + +Sign-in material lives in the OS keyring, under the service `cortex-cli` with the account `auth`: Keychain on macOS, Secret Service on Linux, Credential Manager on Windows. It is deliberately not a file in your home directory, so copying your Cortex home to another machine does not copy your session. Run `cortex login` there instead. See [Sign in to the CLI](/cli/sign-in). + +## Diagnostics + +`cortex --debug` records private, content-free events in the Cortex home `diagnostics/` directory, and `CORTEX_DIAGNOSTICS_DIR` overrides that location. It does not create or overwrite project `debug.txt` files, so running with `--debug` in a repository leaves the repository alone. [CLI troubleshooting](/cli/troubleshooting) describes what the journal may contain. + +## Managing what accumulates + +```bash +cortex compact status # what could be reclaimed +cortex compact run # compact logs, sessions and history +cortex cache size +cortex cache clear +cortex logs --paths # where the logs are +cortex logs --clear +``` + +`cortex debug config` prints the configuration in effect and the files it was merged from, which is the quickest check when you are not sure which root Cortex resolved. `cortex debug paths` lists every path at once. + +## Removing everything + +`cortex uninstall` removes the binary and, unless you pass `--keep-config` or `--keep-data`, the directories above. `--dry-run` shows what it would delete, and `--backup` archives the data first. + + +Sessions, snapshots and personal agents are files, and uninstalling without `--keep-data` deletes them. Take a `--backup` first if there is anything in `sessions/` you may want later. + + +## Related + +- [Configuration](/cli/configuration) +- [Environment variables](/cli/environment-variables) +- [Permission policy](/cli/policy) +- [CLI sessions](/cli/sessions) +- [Sign in to the CLI](/cli/sign-in) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/editor.mdx b/cli/editor.mdx new file mode 100644 index 0000000..3601b66 --- /dev/null +++ b/cli/editor.mdx @@ -0,0 +1,75 @@ +--- +title: "Editor integration" +description: "What exists today: the CLI in your editor's terminal, and an Agent Client Protocol server over stdio. There is no packaged extension." +icon: "pen-to-square" +--- + +If you want Cortex in your editor, read this page before you go looking for a plugin: there is no packaged or marketplace-tested editor extension for Cortex CLI. Two things do work today. You can run the CLI in your editor's built-in terminal, and you can connect an editor that speaks the **Agent Client Protocol** to a local server the CLI starts for exactly that purpose. + +This page covers both, what the protocol server implements and what it does not, why connecting an editor never changes the approval flow, and what an editor adapter is allowed to do. It is deliberately short on promises, because most of this surface is not built yet. + + +There is no packaged or marketplace-tested editor extension. Running Cortex inside an editor's terminal does not establish compatibility with any particular editor, editor fork, or protocol client, and the local client SDK is an integration building block rather than a supported product surface. + + +## Run the CLI in your editor's terminal + +This is the path that works everywhere, because there is nothing to integrate. Open your editor's terminal, run `cortex`, and you get the TUI exactly as you would in any other terminal: the timeline, the composer, the approval prompt, the panels. There is no separate extension UI, no side panel, and no editor commands. + +Everything else in the CLI documentation applies unchanged. The session runs in whatever directory the terminal is in, so start it at your project root, or pass `--cwd`. + +## Connect an editor over the Agent Client Protocol + +For editors that speak the Agent Client Protocol, the CLI can act as the agent side of that conversation: + +```bash +cortex acp --stdio +``` + +Standard input and output is the only supported transport. The command also parses `--port`, `--host`, `--agent`, `--allow-tool` and `--deny-tool`, and then **rejects** them: they fail closed before the server starts rather than running with wider authority than was requested. Treat `cortex acp --stdio` as the whole command surface. + +### What the server implements + +Four methods, and no more: + +| Method | Purpose | +| --- | --- | +| `initialize` | Start the conversation with the client | +| `session/new` | Open a session | +| `session/prompt` | Send a prompt | +| `session/cancel` | Cancel work in progress | + +`session/load`, `session/list`, `models/list` and `agents/list` are **not implemented**. Prompts are text-only. And the load-bearing one: approval requests are **denied** rather than auto-approved, because no permission round trip is advertised to the client. An editor connected this way cannot answer an approval prompt on your behalf, so a task that needs one will not proceed through it. + +## `/ide` inside a session + +The `/ide` slash command, described in the built-in list as managing IDE integration, is the in-session front end for the same protocol over standard input and output. The important half is that approvals are **unchanged**: connecting an editor does not widen the permission model, does not pre-approve anything, and does not bypass the prompt. + +Which editors can be paired, and what the pairing flow looks like, is not documented. If you need that, watch the [changelog](/changelog) rather than guessing from the command's presence. + +## What an editor adapter may do + +If you are the one building the integration, the client SDK gives you a small, deliberate surface. An adapter can start a session, render streamed text and tool observations, keep the returned session id, resume that session for a follow-up the user asked for, and await a cancellation. The SDK does **not** expose write approvals or arbitrary execution-policy settings, so an adapter cannot widen what a session is allowed to do. + +Two requirements from the same guide are worth stating because users can observe them: + +- An adapter must require workspace trust and explicit user initiation. It never starts on activation or because a file was opened. +- The user selects the workspace root, and only explicitly selected context is sent. + +## Not available yet + +Say it plainly, so nobody builds a workflow on it: + +- No packaged editor extension, for any editor. +- No session listing or loading, model listing, or agent listing over the protocol. +- No transport other than standard input and output. +- No editor-side file opening and no diff pane. You review changes in the CLI itself, through the approval prompt and the timeline. See [Modes and permissions](/cli/modes-and-permissions). +- `Cortex pr --apply` remains unsupported. It fails before repository or account access rather than reporting that changes were applied. + +## Related + +- [The TUI](/cli/tui), the interface you get in an editor terminal +- [Modes and permissions](/cli/modes-and-permissions), the approval flow an editor cannot bypass +- [Slash commands](/cli/slash-commands), where `/ide` sits in the built-in list +- [MCP servers in the CLI](/cli/mcp), the supported way to add capabilities +- [Command reference](/cli/reference), the supported command and flag list diff --git a/cli/environment-variables.mdx b/cli/environment-variables.mdx new file mode 100644 index 0000000..3acfcda --- /dev/null +++ b/cli/environment-variables.mdx @@ -0,0 +1,116 @@ +--- +title: "Environment variables" +description: "The CORTEX_* variables Cortex CLI reads, what each one overrides, and where variables sit between config files and flags." +icon: "list" +--- + +Every setting in a Cortex CLI config file can also be set as an environment variable, and a few things can only be set that way. Variables are the right tool when the value changes per shell, per machine or per CI job: which account to use, where the config lives, whether tools run in the cloud or on a connected computer. + +This page lists the variables the CLI reads, grouped the way the product groups them, and says what each one overrides. Values are never documented here: put secrets in your OS keyring or your CI secret store, not in a shell profile that gets committed or shared. + +## Precedence + +Environment variables sit between config files and command-line flags in precedence: a flag beats a variable, a variable beats a config file. So `--sandbox` on the command line wins over anything in your environment, and your environment wins over `~/.cortex/config.toml`. + +## Locations + +| Variable | Effect | +| --- | --- | +| `CORTEX_HOME` | Root for config and data. Default `~/.cortex`. Checked for writability at startup. | +| `CORTEX_CONFIG_DIR` | Cortex home root. Checked before `CORTEX_HOME`, and it moves the whole root, not just the config file | +| `CORTEX_CONFIG` | Path to a specific config file, overriding the file path outright | +| `CORTEX_DATA_DIR` | Data directory for sessions and history | +| `CORTEX_CACHE_DIR` | Cache directory | +| `CORTEX_DIAGNOSTICS_DIR` | Where the diagnostic journal is written. Unset means no journal is created. | +| `CORTEX_ORG_POLICY_DIR` | Directory holding a managed `policy.json` | + +The home directory resolves in the order `CORTEX_CONFIG_DIR`, then `CORTEX_HOME`, then `~/.cortex`. See [Data locations](/cli/data-locations) for what ends up in each directory. + +## Account + +| Variable | Effect | +| --- | --- | +| `CORTEX_API_KEY` | API key, for headless and CI use | +| `CORTEX_AUTH_TOKEN` | Session or bearer token. Checked before `CORTEX_API_KEY`. | +| `CORTEX_API_URL` | Base URL of the Cortex API. Defaults to `https://api.cortex.foundation`. Intended for operators and tests. | + +Interactive use should prefer `cortex login`, which stores the session in the OS keyring. See [Sign in to the CLI](/cli/sign-in). + +## Where tools run + +| Variable | Effect | +| --- | --- | +| `CORTEX_COMPUTER` | Where tools run. Unset, or `cloud`, uses Cortex Cloud. Set `this_pc` (aliases `this-pc`, `local`, `paired`, `connected`) or `ssh`. | +| `CORTEX_SSH_HOST` | SSH target. Setting it selects the SSH runtime. | +| `CORTEX_SSH_TARGET` | Alias of `CORTEX_SSH_HOST` | + + +This PC and SSH require an already connected Code session. Cortex will not create one for you and will not quietly substitute Cortex Cloud. See [Cloud, This PC, and SSH](/cli/hosts). + + +## Model selection + +| Variable | Effect | +| --- | --- | +| `CORTEX_MODEL` | Default model | +| `CORTEX_DEFAULT_MODEL` | Fallback default model | +| `CORTEX_PROVIDER` | Provider id. Defaults to `cortex`. | +| `CORTEX_MAX_TOKENS` | Default response length cap | +| `CORTEX_TEMPERATURE` | Default sampling temperature | +| `CORTEX_PRICING_` | Per-model price used in cost reporting | + +## Logging and diagnostics + +| Variable | Effect | +| --- | --- | +| `CORTEX_LOG_LEVEL` | Log verbosity for a subcommand: `error`, `warn`, `info`, `debug`, `trace` | +| `RUST_LOG` | Overrides the tracing filter entirely when set, for example `RUST_LOG=debug cortex plugin list` | +| `RUST_BACKTRACE` | Standard backtrace control | +| `NO_COLOR` | Disable colour. `--color never` sets this for child processes. | +| `CORTEX_GIT_TIMEOUT_SECS` | Timeout for git operations | + +`CORTEX_DIAGNOSTICS_DIR` is the opt-in switch for writing diagnostic files at all. [CLI troubleshooting](/cli/troubleshooting) has the allowlist, the size caps and the retention window. + +## Set for you, not by you + +These are populated by Cortex for the processes it spawns. A plugin can read them; you should not set them yourself. + +| Variable | Available to | +| --- | --- | +| `CORTEX_PLUGIN_ARGS` | Plugin invocations: the arguments the call was made with, as JSON | + +Cortex also sets a small number of further variables for its own task routing. They are not a supported surface and setting them yourself is not meaningful. + +Hooks do not get an environment of their own. A hook belongs to a plugin and runs inside the plugin runtime rather than as a command Cortex spawns for it, so there are no hook-specific variables to read. See [Hooks](/cli/hooks). + +## Standard variables Cortex respects + +| Variable | Used for | +| --- | --- | +| `EDITOR`, `VISUAL` | Opening an editor for `cortex agent edit`, `cortex workspace edit` and similar | +| `SHELL` | Shell completion setup and diagnostics | +| `HTTPS_PROXY`, `HTTP_PROXY` (and the lowercase spellings) | Outbound HTTP from `cortex scrape` | +| `SUDO_USER`, `SUDO_UID` | Resolving your real home directory when running under `sudo` | +| `PATH`, `TERM`, `LANG`, `LC_ALL`, `USER` | Reported in diagnostics output | +| `XDG_*` | Legacy path resolution | + +## Checking what is in effect + +```bash +cortex config +``` + +That prints the effective configuration after every layer has been merged, which is the fastest way to find out whether a variable or a config file won. If the answer surprises you, check for a project `.cortex/config.toml`: it overrides your own config file, though not your environment. See [Configuration](/cli/configuration). + + +The CLI also reads a handful of capture and test variables that exist for people working on the CLI itself. They are not part of the supported surface. The only one a normal user tends to want is `CORTEX_CURSOR_BLINK`, which overrides blink behaviour in the composer. + + +## Related + +- [Configuration](/cli/configuration) +- [Data locations](/cli/data-locations) +- [Permission policy](/cli/policy) +- [Headless and one-shot runs](/cli/headless) +- [CI cookbook](/cli/ci) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/extend.mdx b/cli/extend.mdx deleted file mode 100644 index 1596992..0000000 --- a/cli/extend.mdx +++ /dev/null @@ -1,203 +0,0 @@ ---- -title: "Extend the CLI" -description: "MCP servers, skills, agents and subagents, hooks, plugins, custom commands, and themes — every extension point in the Cortex CLI." -keywords: ["MCP", "plugins", "hooks", "skills", "agents", "themes"] ---- - -The CLI ships with the tools a coding agent needs. You extend it in six ways: connect **MCP servers** for more tools, write **skills** for how a job is done, define **agents** for who is working, run **hooks** on lifecycle events, install **plugins**, and add **custom commands**. - -## MCP servers - -Cortex is a Model Context Protocol client. Connecting a server adds its tools to the set the agent can call. - -```bash -# a local process (stdio) — everything after -- is the command Cortex launches -cortex mcp add myserver -- npx @example/mcp-server -cortex mcp add myserver --env API_HOST=example.com -- node server.js -v - -# a remote server over streamable HTTP -cortex mcp add myapi --url https://mcp.example.com/mcp --bearer-token-env-var MY_API_TOKEN - -# a remote server over SSE -cortex mcp add myevents --sse https://mcp.example.com/sse -``` - -The `--` matters: without it, flags meant for the server are parsed as Cortex flags. `--bearer-token-env-var` takes the **name** of an environment variable, so the token never lands in a config file. URLs on `localhost` or private ranges are rejected unless you pass `--allow-local`. - -```bash -cortex mcp list --all # include disabled servers -cortex mcp get -cortex mcp enable / disable / rename / remove -cortex mcp debug # try the connection -cortex mcp debug --test-auth --no-cache -``` - -In the TUI, `/mcp` (or **Ctrl+E**) opens the manager, `/mcp-tools` lists each server's tools, `/mcp-auth` handles servers that need sign-in, and `/mcp-reload` re-reads the configuration. - - - Cortex CLI MCP server manager listing four servers and their connection state - - -A tool `search` from server `myserver` is presented to the agent as `mcp__myserver__search` — that is the name to use with `--enabled-tools`, `--disabled-tools`, and the `permission.mcp` table. Configuration lives under `mcp_servers` in `config.toml`: - -```toml -[mcp_servers.myapi] -enabled = true - -[mcp_servers.myapi.transport] -type = "http" # stdio, http, sse, or web_socket -url = "https://mcp.example.com/mcp" -bearer_token_env_var = "MY_API_TOKEN" -``` - -Chat has its own HTTP-only MCP attachment under **Settings → Integrations** — see [Tools and connectors](/chat/tools). - -## Skills - -A skill is a bundle of instructions the agent loads on demand through its `UseSkill` tool — your deployment checklist, your migration procedure, the way your team writes commit messages. Built-in skills: `git`, `code-quality`, `file-operations`, `debugging`, `security`, `planning`. - -A skill is a directory with a `SKILL.md`: - -```markdown ---- -name: release-checklist -description: Cut a release of this service, from version bump to announcement -args: - - name: version - description: The semantic version being released - required: true -tools: - - Read - - Grep - - Execute ---- - -# Release checklist - -1. Confirm `main` is green. -2. Bump the version in `Cargo.toml` and `VERSION`. -``` - -`description` decides whether a skill ever gets used — write it as the situation it applies to. Skills are found, in order, in built-ins, `./SKILL.md`, `/.agents//`, `/.agent//`, `/.cortex/skills//`, and `~/.cortex/skills//`. - -`/skills` lists them, `/skill [args]` forces one, `/skill-reload` re-reads after editing, and `cortex debug skill ` shows how one resolves. Gate them with `[permission.skill]`. - - - Cortex CLI skills picker listing project and user skills - - -Bot has its own first-party skills — see [Bot skills](/bot/skills). - -## Agents and subagents - -An agent is a named configuration: which model, how much reasoning, which tools. - -| Built-in | Kind | Behaviour | -| --- | --- | --- | -| `build` | Primary | Full access. The default. | -| `plan` | Primary | Read-only. Investigates and proposes. | -| `explore` | Subagent | Read-only investigation, capped at 15 steps | -| `general` | Subagent | General-purpose worker; cannot delegate further | -| `research` | Subagent | Read-only research | - -```bash -cortex agent list --primary / --subagents -cortex agent show -cortex agent create --generate "reviews Rust for concurrency bugs" -cortex agent edit -cortex run --agent reviewer "review the last commit" -``` - -An agent file is markdown with frontmatter; the body is its system prompt: - -```markdown ---- -name: reviewer -description: Reviews changes for correctness and missing tests -model: inherit -reasoning_effort: high -tools: read-only # read-only | edit | execute | web | mcp | all, or an explicit list -max_steps: 25 ---- - -You review code changes. Read the diff and the surrounding files, then report -what is wrong, what is missing and what you would change. Do not edit anything. -``` - -Agent files are found in `/.agents/`, `/.agent/`, `/.cortex/agents/`, then `~/.cortex/agents/`; project agents override personal ones. Mention one in a prompt with `@reviewer …`, or set `current_agent` in config. - -**Subagents** are what the main agent delegates to through its `Task` tool, in one of three roles — `explore`, `plan`, or `worker`. A child task cannot spawn children, ask you questions, or message you; everything reports back through the parent. `/jobs` shows what is running. - -## Hooks - -Hooks run your own commands when something happens — a file was edited, a tool is about to run, the session ended. They wire Cortex into a formatter, a linter, a notifier, or an audit log. - -| Event | Fires | -| --- | --- | -| `SessionStart` · `SessionEnd` · `SessionCompleted` | Session lifecycle | -| `UserPromptSubmit` | You submit a prompt | -| `PreToolUse` · `PostToolUse` · `PostToolUseFailure` | Around a tool | -| `PermissionRequest` | An approval is requested | -| `FileCreated` · `FileEdited` · `FileDeleted` | The agent changed a file | -| `SubagentStart` · `SubagentStop` | Delegation | -| `PreCompact` · `Notification` · `Stop` | Housekeeping | - -```json -{ - "file_edited": { - "*.rs": [{ "command": ["rustfmt", "{file}"], "timeout": 15 }] - }, - "pre_tool_use": [ - { - "command": ["./scripts/deny-generated.sh", "{file}"], - "tool_matcher": "Edit|Create|ApplyPatch", - "timeout": 5 - } - ] -} -``` - -`command` is an array, not a shell string. Placeholders `{file}`, `{path}`, `{session_id}`, `{message_id}` are also exported as `CORTEX_FILE`, `CORTEX_SESSION_ID`, `CORTEX_MESSAGE_ID`. A failing `PreToolUse` hook stops the tool call — that is how you block writes to generated files. `/hooks` manages them from the TUI. - -## Plugins - -WebAssembly plugins add tools and hooks inside a sandboxed runtime. - -```bash -cortex plugin list -cortex plugin install -cortex plugin enable / disable / remove -cortex plugin new --typescript # scaffold -cortex plugin dev --watch # develop -cortex plugin build / validate / publish -``` - -`/plugins` covers install, enable, and disable from the TUI. Configuration keys: `plugins`, `plugin_dirs`, `plugin_settings`. - - - Cortex CLI plugins manager listing installed plugins - - -## Custom commands - -Markdown files under `.cortex/commands/` become slash commands; `/commands` lists them. See [Slash commands](/cli/slash-commands#your-own-commands). `cortex alias set` adds shell-level aliases for `cortex` subcommands. - -## Themes - -| Theme | Notes | -| --- | --- | -| **Cortex Night** (`dark`) | Default. Grey chrome on a black canvas; Cortex green `#1F4945` marks the focused control. | -| **Cortex Day** (`light`) | Light background, dark text | -| **Ocean Dark** (`ocean_dark`) | Deep blue and cyan | -| **Monokai** (`monokai`) | Classic editor colours | - -`/theme` opens the picker — moving the selection previews live, **Esc** reverts — and `/theme monokai` switches directly. In config: `[tui.theme] name = "ocean_dark"`; `/reload-config` picks it up without restarting. - -## Editor integration - -`cortex acp --stdio` starts an Agent Client Protocol server for editors that speak it; `--allow-tool` and `--deny-tool` narrow what the editor may invoke. Running `cortex` inside an editor's terminal gives you the TUI as it is — there is no separate extension UI. - -## Related - -- [Configuration](/cli/configuration) — where all of this is stored. -- [Modes and permissions](/cli/modes-and-permissions) — gating skills, MCP servers, and commands. diff --git a/cli/goal.mdx b/cli/goal.mdx index 11e611a..0cbe629 100644 --- a/cli/goal.mdx +++ b/cli/goal.mdx @@ -1,81 +1,100 @@ --- title: "Goals" -description: "/goal attaches a long-horizon objective to the session. It survives compaction and resume while the agent keeps planning, acting, and verifying." -keywords: ["objective", "long running", "/goal"] +description: "Attach a long-horizon objective to a CLI session with /goal: it survives compaction and resume, carries a turn budget, and completes on evidence" +icon: "bullseye" --- -A normal turn ends when the model stops. A **goal** does not: `/goal` attaches an objective to the session, and the agent keeps working toward it across turns — planning, acting, verifying — until the work is **evidence-complete**, until you pause or clear it, or until the budget runs out. The goal survives the end of a turn, context compaction, and closing and resuming the TUI. +A normal turn ends when the model stops. A **goal** does not. `/goal` attaches one objective to the session, and the agent keeps working toward it across turns, planning, acting and verifying, until it can show evidence that the work is done, until you pause or clear it, or until its turn budget runs out. The objective is session state, so it survives the end of a turn, context compaction, and closing and resuming the terminal app. -This is Cortex session state, not a second coding provider. Agent mode still talks to the Cortex API; `/goal` is harness state — persist, continue, wrap up. +This page covers the commands, the chip that reports progress, the five states a goal can be in, how completion is decided, the turn budget, where the goal is kept, and when a goal is the right tool instead of a single turn or a headless run. -`/goal` landed on the CLI main branch on 8 September 2026 ([CortexLM/cli #54](https://github.com/CortexLM/cli/pull/54)) and ships with the next tagged release after 0.1.10. If `/goal` is not in your palette yet, run `cortex upgrade` once that release is out. +`/goal` is a recent addition to the CLI. If it does not appear when you type `/`, run `cortex upgrade` and try again. +## Set a goal + + + + Type `/goal ` in the composer. Describe an outcome that can be checked, not a single edit: *ship the rate limiter and prove it with tests* rather than *open the rate limiter file*. + + + A goal chip appears immediately after the mode chip on the composer, reading `Goal · 0/8` before the first turn and counting up from there. + + + The agent continues between turns while the goal is `active`. Type `/goal` on its own at any point to see the objective, the state, the progress so far and the remaining budget. + + + `/goal pause` stops the automatic continuation and leaves the objective in place. `/goal resume` picks it up again. `/goal clear` deletes it. + + + ## Commands | Command | Effect | | --- | --- | | `/goal ` | Create or replace the active goal and start a kickoff turn | -| `/goal` | Show the objective, state, progress, and budget | -| `/goal pause` | Stop auto-continuation. Only you can pause; the model cannot. | -| `/goal resume` | Resume a paused or blocked goal if budget remains | +| `/goal` | Show the objective, the state, the progress and the budget | +| `/goal pause` | Stop the automatic continuation. Only you can pause; the model cannot | +| `/goal resume` | Pick a paused or blocked goal back up while budget remains | | `/goal clear` | Delete the persisted goal | -A reserved word is only special when it is the **entire** argument. `/goal pause the deploy` sets an objective; it does not pause. + +A reserved word is only special when it is the **entire** argument. `/goal pause the deploy` sets an objective called *pause the deploy*; it does not pause anything. To pause, type `/goal pause` and nothing else. + -## What you see +## The chip and the five states -The composer carries a chip with the goal's progress, painted in Cortex green on the border next to the mode: +The chip sits next to the mode chip on the composer border, so the goal is visible in every turn without opening a panel. - - Cortex CLI composer with the Goal · 2/8 chip on its border - +| State | Chip | What it means | +| --- | --- | --- | +| `active` | `Goal · 2/8` | The agent continues automatically between turns. The pair is turns used against the turn budget | +| `paused` | `Goal · paused` | You stopped the automatic continuation. Resume when you are ready | +| `complete` | `Goal · done` | The agent submitted evidence and it was accepted | +| `budget_limited` | `Goal · budget` | The turn budget ran out before the objective was met | +| `blocked` | `Goal · blocked` | The agent reported that it cannot proceed without you | -The chip reads `Goal · 2/8` while active, and `paused`, `done`, `budget`, or `blocked` in the other states. +## Completion is evidence-based - - Cortex CLI composer with the Goal · done chip on its border - +The agent reports progress through a dedicated `UpdateGoal` tool rather than by saying it is finished. That call carries a `status` of `active`, `blocked` or `complete`, optionally a `progress` note and a `reason`, and optionally `evidence`. Each piece of evidence has a `kind` of `file`, `command` or `test`, plus a detail naming the file, the command or the test in question. -## States +Two rules follow from that, and they are the point of the feature: -| State | Meaning | -| --- | --- | -| `active` | The agent continues automatically between turns | -| `paused` | You stopped auto-continuation; resume when ready | -| `complete` | Evidence-complete — see below | -| `budget_limited` | The turn or token budget ran out; resume with a fresh budget if you want more | -| `blocked` | The agent needs something from you; resume after you provide it | +- **Marking a goal complete requires a reason and usable evidence.** A confident paragraph is not enough to move the chip to `Goal · done`. +- **The model cannot pause a goal.** `active`, `blocked` and `complete` are the only states it can set. Pausing is yours alone. -## Evidence, not vibes +A goal does not change what the agent is allowed to do. Every turn it takes still runs under the mode you are in, your approval policy and the sandbox, so commands that would prompt for approval still prompt. See [Modes and permissions](/cli/modes-and-permissions). -Completion is evidence-based. To mark a goal done the model must call `UpdateGoal` with a reason **and** at least one of: a file path, a command, or a test. A confident paragraph is not enough. +## The turn budget -## Budget +A goal carries a turn budget, **8 turns** by default, which is the right-hand number on the chip. Close to the limit the next continuation is asked to wrap up what it has rather than open new scope. When the budget is used up the goal moves to `budget_limited`, the chip reads `Goal · budget`, and the automatic continuation stops; set the goal again if you want it to carry on with a fresh budget. -The default budget is **8 turns**. Near the limit — one turn left, or 85% of a token cap — the next continuation asks the agent to wrap up rather than open new scope. +For work that should run unattended with a hard ceiling instead, use a headless run with its own turn and time limits. See [Headless and one-shot runs](/cli/headless). -## Where it is stored +## Where the goal is kept -`goal.json` lives next to the session files: +The goal is written next to the rest of the session's files, in the Cortex home directory: ```text ~/.cortex/sessions/{session-id}/goal.json ``` -Resuming the session reloads it. See [Sessions](/cli/sessions) and [Configuration → Data locations](/cli/configuration#data-locations). +Because it is a file beside the session, resuming the session reloads the objective, the state and the progress, and compacting the conversation does not lose it. See [CLI sessions](/cli/sessions) and [Data locations](/cli/data-locations). ## When to use a goal -| Situation | Goal or not | +| Situation | Use | | --- | --- | -| *Fix this one test* | A normal turn | -| *Ship the rate limiter and prove it with tests* — several files, a build, tests | **Goal** | -| Something you want done overnight in CI | [`cortex exec`](/cli/headless) with `--max-turns` and `--timeout` | -| Scheduled, repeated work on a computer | A [Bot routine](/bot/routines) | +| *Fix this one failing test* | A normal turn. A goal adds nothing | +| *Ship the rate limiter and prove it with tests*, several files, a build and a test run | A goal | +| Work that has to run unattended, in a job that reports an exit code | [`cortex exec`](/cli/headless) with its turn and time limits | +| Repeated work on a schedule | A [Bot routine](/bot/routines) | ## Related -- [Modes and permissions](/cli/modes-and-permissions) — a goal still runs under your approval policy and sandbox. -- [Sessions](/cli/sessions) — resume brings the goal back. +- [Modes and permissions](/cli/modes-and-permissions): the approval policy and sandbox a goal still runs under +- [CLI sessions](/cli/sessions): resuming a session brings its goal back +- [Tools the agent uses](/cli/tools): the `UpdateGoal` tool and everything else the agent can call +- [Slash commands](/cli/slash-commands): the rest of what you can type after `/` +- [Headless and one-shot runs](/cli/headless): the unattended equivalent diff --git a/cli/headless.mdx b/cli/headless.mdx index 7ef9f59..215d483 100644 --- a/cli/headless.mdx +++ b/cli/headless.mdx @@ -1,49 +1,65 @@ --- title: "Headless and one-shot runs" -description: "cortex exec for CI and scripts — autonomy levels, JSON output, turn and time limits — and cortex run for a single streamed request from your own shell." -keywords: ["CI", "automation", "exec", "scripts", "JSON output"] +description: "cortex exec for scripts and automation, cortex run for a single streamed answer: autonomy levels, output formats, limits and exit codes" +icon: "gears" --- -Two entry points work without a terminal, so they are safe in pipelines where the TUI refuses to start: +Two commands work without a terminal to draw into, so they are safe in pipelines and scripts where the TUI would refuse to start. `cortex exec` is the headless one: an autonomy ceiling, machine-readable output, turn and time limits, and a non-zero exit when anything goes wrong. `cortex run` is the one you type yourself: one prompt, one streamed answer, with sessions and sharing. + +This page covers which of the two to reach for, how autonomy works when there is nobody to answer an approval prompt, the output formats and what the result document contains, the limits you should always set, and the exit-code contract that a script has to respect. For pipeline recipes, see the [CI cookbook](/cli/ci). | Command | Use it for | | --- | --- | -| `cortex exec` | CI, scripts, automation. Autonomy levels, structured output, turn and time limits. Fails closed with a non-zero exit. | +| `cortex exec` | Automation and scripts. Autonomy levels, structured output, turn and time limits. Fails closed with a non-zero exit. | | `cortex run` | A single request from your shell. Streams a formatted answer, continues sessions, can share the result. | -Both use the **Cloud** runtime unless `CORTEX_COMPUTER` selects This PC or SSH — see [Configuration](/cli/configuration). +Both create a **Cloud** session unless `CORTEX_COMPUTER` or `CORTEX_SSH_HOST` selects another host. See [Cloud, This PC, and SSH](/cli/hosts). ## `cortex exec` ### Give it a prompt ```bash -cortex exec "explain what src/main.rs does" +cortex exec "explain what the storage layer does" cortex exec -f prompt.txt echo "review the diff" | cortex exec ``` ### Autonomy -There is nobody to ask in headless mode, so `--auto` is the safety control that matters. +There is nobody to ask in a headless run, so the run's authority has to be decided before it starts. `--auto` is that decision: | Level | Allows | | --- | --- | | `read-only` | Reading, searching, analysing. No file changes, no commands. **Default.** | -| `low` | Basic file operations — documentation, formatting, comments | -| `medium` | Adds package installation, builds, local git operations | -| `high` | Full access, including operations that reach outside the workspace | +| `low` | Basic file operations: documentation, formatting, comments. Refused, see below | +| `medium` | Adds package installation, builds, local git operations. Refused, see below | +| `high` | Never asks, and allows workspace writes with network access. Its own description is git push, deployments and other sensitive operations | ```bash cortex exec --auto read-only "review this code for security issues" -cortex exec --auto low "fix all formatting issues in src/" -cortex exec --auto medium "implement unit tests for the auth module" +cortex exec --auto high "implement unit tests for the auth module" +``` + +Start at `read-only` and raise the level only as far as the task genuinely needs. A review job never needs write access. In this build `cortex exec` accepts `read-only` and `high` only: `--auto low` and `--auto medium` stop the run before anything is submitted, with `--auto low/medium (client risk thresholds) is not supported by the Code service contract. No turn was submitted.` + +You can narrow the run further, independently of the level, by naming the tools it may use: + +```bash +cortex exec --list-tools +cortex exec --list-tools --enabled-tools Read,Grep,Glob ``` +Tool names are case-sensitive, and `--list-tools` prints what a given run actually has. `--enabled-tools` and `--disabled-tools` are accepted only alongside `--list-tools`; on a run that submits a turn they stop it first, with `--enabled-tools is not supported by the Code service contract. No turn was submitted.` To narrow what a real run may do, set `--auto` and the `[permission]` table. See [Tools the agent uses](/cli/tools) and [Permission policy](/cli/policy). + -`--skip-permissions-unsafe` bypasses every permission check and cannot be combined with `--auto`. Use it only in a disposable environment — an isolated container or an ephemeral runner with no credentials. Never on a developer machine, a shared runner, or anything holding secrets. +`--skip-permissions-unsafe` is declared on `cortex exec` but refused: it stops the run with `--skip-permissions-unsafe is not supported by the Code service contract. No turn was submitted.` It is also declared as conflicting with `--auto`, so the two cannot be passed together. There is no flag that removes permission checks from a headless run. Set the autonomy level you want, and pin the rest with the `[permission]` table. +### Hooks are not approvals + +A hook cannot stand in for your consent. No hook can approve a tool call, and adding a hook does not make a run more permitted than its policy allows. A hook is not a way to stop one either: hooks belong to a plugin and do not fire around the tool calls a run makes. What a headless run may do is decided by `--auto`, the tool allow and deny lists, and the permission policy, before the first turn. See [Hooks](/cli/hooks) and [Permission policy](/cli/policy). + ### Output formats `-o` / `--output-format`: @@ -54,23 +70,23 @@ cortex exec --auto medium "implement unit tests for the auth module" | `json` | One JSON document with the final result | | `stream-json` | JSON Lines, one event per line, as execution proceeds | | `stream-jsonrpc` | JSON-RPC streaming for multi-turn conversations | +| `debug` | Deprecated alias for `stream-json` | ```bash -cortex exec -o json "list all TODO comments" | jq -r '.response' +cortex exec -o json "list all TODO comments" > result.json cortex exec -o stream-json "run the test suite" | tee run.jsonl ``` -`--response-format text|json|json_object` shapes what the model returns; `--output-schema` takes inline JSON or a schema file for structured output. +`--input-format` selects how the prompt is fed in. It takes `text`, the default; `stream-jsonrpc` for the JSON-RPC protocol; and `stream-jsonl` for one JSON object per line, one line per turn, with no envelope or ids and the connection held open between turns. `--response-format` is accepted only as `text`, which is what it already is, and `--output-schema` is refused outright. When you need a validated result document, use `-o json` with `--json-schema`. ### Add context | Flag | Effect | | --- | --- | -| `--include ` / `--exclude ` | Filter files in the context; repeatable | +| `--include ` / `--exclude ` | Filter the files in the context; repeatable | | `--git-diff` | Include the current git diff | -| `--url ` | Fetch a URL into the context; repeatable | +| `--url ` | Fetch a URL into the context | | `--clipboard` | Read the clipboard | -| `-i`, `--image ` | Attach an image; repeatable | ### Limits @@ -79,116 +95,106 @@ cortex exec --timeout 1800 "refactor the storage layer" # default 600 seconds cortex exec --max-turns 10 "quick task" # default 100 turns ``` -A turn is one complete request/response cycle with the model. - -### Choose tools - -```bash -cortex exec --list-tools -cortex exec --enabled-tools Read,Grep,Glob "map the module structure" -cortex exec --disabled-tools Execute "suggest a fix without running anything" -``` +A turn is one complete request and response cycle with the model. Both defaults exist so a runaway run eventually stops, but in automation you should set them yourself: they are the difference between a failed job and a runner that hangs. ### Other flags | Flag | Effect | | --- | --- | -| `-m`, `--model ` | Model for this run | -| `-r`, `--reasoning-effort ` | Reasoning effort | -| `--use-spec` / `--spec-model ` | Run through [Spec mode](/cli/modes-and-permissions#spec-mode) | +| `--use-spec` | Run through [Spec mode](/cli/plan-mode) | | `-s`, `--session-id ` | Continue an existing session | -| `--cwd ` | Working directory | -| `--system ` | Replace the system prompt | -| `--max-tokens ` | Cap the response | | `--echo` | Include the prompt in the output | -`cortex exec --help` has the complete list. +A further set of flags is declared on `cortex exec` but refused before a turn is submitted, each with ` is not supported by the Code service contract. No turn was submitted.`: `--skip-permissions-unsafe`, `--output-schema`, `--max-tokens`, `--frequency-penalty`, `--presence-penalty`, `--stop`, `--logprobs`, `--n`, `--best-of`, `--user`, `--suffix`, `--spec-model`, `-i`/`--image`, and `--response-format` or `-r`/`--reasoning-effort` with anything but their default. `cortex exec --help` lists what is declared; this page tells you which of it runs. ## `cortex run` -Interactive-adjacent: streams a formatted answer into your terminal and understands sessions. +`cortex run` streams a formatted answer into your terminal and understands sessions. It is the one to use when a person is reading the output. ```bash cortex run "explain the release process" cortex run --continue "now write it up as a checklist" cortex run --session "and add the rollback steps" -cortex run --share "summarise today's changes" # prints a share URL -cortex run --agent reviewer --format json "review src/auth" +cortex run --worktree --ephemeral "try the risky refactor and show me the diff" +cortex run --agent reviewer --format json "review the auth module" cortex run -f context.md -o answer.md "turn this into a runbook" ``` -`--format default|json|jsonl` (alias `--output`); `--copy` puts the answer on the clipboard; `--output-file` writes it to disk; `--notification` raises a desktop notification when done. - -## Examples - -### GitHub Actions - -```yaml -name: Cortex review -on: [pull_request] - -jobs: - review: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Review the diff - env: - CORTEX_API_KEY: ${{ secrets.CORTEX_API_KEY }} - run: | - cortex exec --auto read-only --git-diff \ - --timeout 600 --max-turns 20 \ - "Review this diff for bugs, security issues and missing tests" +| Flag | Effect | +| --- | --- | +| `--format ` | Output format; `--output` is an alias | +| `-c`, `--continue` / `-s`, `--session ` | Continue the most recent session, or a named one | +| `--agent ` | Agent to use | +| `--command ` | Run a predefined command instead of a prompt | +| `-f`, `--file ` | Attach a file; repeatable | +| `-C`, `--copy` / `-o`, `--output-file ` | Copy the answer to the clipboard, or write it to a file | +| `--cwd ` | Working directory override | +| `--worktree [DIR]` | Run in an isolated git worktree | +| `--plugin-dir ` | Extra plugin folder, or a single plugin; repeatable | +| `--timeout ` | Time limit. `0` means no timeout, and that is the default | +| `--dry-run` | Preview what would be sent, with estimated token counts, without executing | +| `--system ` | Client instructions sent as additional user context, not a service system override | +| `--stream` / `--no-stream`, `-q`, `--quiet`, `--no-progress`, `--bare` | Output behaviour. `--bare` prints the result and errors and nothing else | +| `--ephemeral` | Persist no session file, so nothing is left for `cortex sessions` or `--continue`. Cannot be combined with `-c`/`--session` | +| `--json-schema` | Validate the result document against the shipped JSON Schema. Needs `--format json` | +| `--bash-edit-diff` | Attach unified diffs of the files the Execute tool changed | +| `-v`, `--verbose` | Verbose output | +| `-n`, `--notification` | Desktop notification when finished | + +`cortex run` also declares a set of flags it refuses before submitting a turn, each with ` is not supported by the Code service contract. No turn was submitted.`: `--share`, `--title`, `--port`, `--add-dir`, `--schema`, `--max-tokens`, `--retry`, `--no-cache`, `-t`/`--temperature`, `--top-p`, `--top-k`, `--seed`, `--frequency-penalty`, `--presence-penalty`, `--stop`, `--logprobs`, `--n` and `--best-of`. `--attach ` has its own message, `--attach is not supported by this runtime. No local session was started.` Sampling, retries and sharing are therefore not available from `cortex run` on this build. + +Global options that matter in a script: `--color`, `-L`/`--log-level`, `--debug`, `-c`/`--config KEY=VALUE` (repeatable) and `-p`/`--profile`. + +## Read the result + +`cortex run --format json` prints one document: + +```json +{ + "type": "result", + "session_id": "...", + "message": "the final answer", + "events": 12, + "success": true, + "interrupted": false, + "complete": true, + "truncated": false, + "finish_reason": "stop" +} ``` -`cortex github install` scaffolds workflows for pull-request review and issue automation if you would rather not write the YAML. +Those four booleans are there so a parser can tell the cases apart: a run can fail, be interrupted, or be truncated, and they are not the same thing. `cortex exec -o json` prints the same idea with its own field names, including `subtype`, `is_error`, `duration_ms` and `num_turns`, so read the document your command actually produced rather than assuming a shared shape. -### GitLab CI +Continuing a session across invocations is a matter of keeping the id: -```yaml -code-review: - script: - - cortex exec --auto read-only -o json "Review the code changes" > review.json - artifacts: - paths: [review.json] +```bash +session=$(cortex exec -o json "analyse this codebase" | jq -r '.session_id') +cortex exec -s "$session" "now focus on the auth module" ``` -### A shell script +## Exit codes -```bash -#!/usr/bin/env bash -set -euo pipefail - -if git diff --quiet; then - echo "No changes to review" - exit 0 -fi - -cortex exec --auto read-only --git-diff \ - --timeout 300 --max-turns 20 \ - -o json "Review these changes for issues" \ - | jq -r '.response' -``` +| Code | Meaning | +| --- | --- | +| `0` | The task completed | +| non-zero | The run failed, was interrupted, was truncated, or the service was unreachable | -### Continue a session across invocations +A non-zero exit is the contract. Do not wrap a failing run in `|| true`, or you have built a pipeline that cannot fail. -```bash -session=$(cortex exec -o json "analyse this codebase" | jq -r '.session_id') -cortex exec -s "$session" "now focus on the auth module" -``` +Headless runs also fail closed when the coding service cannot be reached: the run prints `The coding service is temporarily unavailable`, exits non-zero, and never falls back to running a model locally. ## Practices worth keeping -1. **Start at `read-only`** and raise autonomy only when the task needs it. A review job never needs write access. -2. **Always set `--timeout` and `--max-turns` in CI.** They are the difference between a failed job and a runner that hangs. -3. **Use `-o json` or `-o stream-json`** when something downstream parses the output. -4. **Keep the transcript.** `-o stream-json … | tee run.jsonl` is your audit trail. -5. **Pass credentials through the environment**, never on the command line. See [Sign in](/cli/sign-in). +1. **Start at `read-only`** and raise autonomy only when the task needs it. +2. **Always set `--timeout` and `--max-turns`** in anything unattended. +3. **Use a JSON format** whenever something downstream parses the output. +4. **Keep the transcript.** `-o stream-json ... | tee run.jsonl` is your audit trail. +5. **Pass credentials through the environment**, never on the command line. See [Sign in to the CLI](/cli/sign-in). ## Related -- [Modes and permissions](/cli/modes-and-permissions) -- [Sessions](/cli/sessions) -- [Cortex Security](/code/security) — the GitHub App alternative for pull-request review. +- [CI cookbook](/cli/ci), pipeline recipes and secret handling +- [Modes and permissions](/cli/modes-and-permissions), the controls `--auto` maps onto +- [Permission policy](/cli/policy), rules that apply before a run starts +- [Cloud, This PC, and SSH](/cli/hosts), where an unattended run executes +- [Command reference](/cli/reference), the supported command surface group by group diff --git a/cli/hooks.mdx b/cli/hooks.mdx new file mode 100644 index 0000000..16979cc --- /dev/null +++ b/cli/hooks.mdx @@ -0,0 +1,123 @@ +--- +title: "Hooks" +description: "How a hook reaches a CLI session: the plugin manifest block, the events that fire, the order they run in, and why a hook can deny but never approve" +icon: "link" +--- + +A **hook** lets a plugin act when something happens in a session: a tool is about to run, a tool has finished, a session has started. A hook is declared by a plugin, in that plugin's manifest, and it runs inside the plugin runtime. There is no separate hooks file to write by hand. + +This page covers where a hook is declared, which events actually fire today, the order hooks run in, what a hook is allowed to change, and the one thing a hook can never do: approve something on your behalf. + +## Where a hook is declared + +Hooks live in the plugin manifest, as one `[[hooks]]` block per hook: + +```toml +[[hooks]] +hook_type = "tool_execute_before" +priority = 50 +pattern = "*.rs" +``` + +A hook block has exactly four keys, and the manifest refuses any key it does not recognise rather than ignoring it: + +| Key | Required | What it does | +| --- | --- | --- | +| `hook_type` | yes | Which event this hook listens for | +| `priority` | no | Ordering, default `100`. A **lower** number runs earlier | +| `pattern` | no | Narrows the hook to matching subjects. Omit it to match everything | +| `function` | no | The entry point in the plugin to call for this hook | + +Because a hook belongs to a plugin, installing a plugin is what installs its hooks. Creating, building, validating and installing a plugin is covered on [CLI plugins](/cli/plugins). + +## What fires today + +This is the part to read before you design anything around hooks. The manifest accepts a broad set of event names, but only some of them are dispatched by the shipped build. + +Hooks run in two situations: + + + + Starting the CLI loads your plugin directories into the plugin runtime and fires `session_start`. A plugin that refuses here stops the runtime from coming up. + + + `cortex plugin run` dispatches the full chain around the call: `session_start`, then `tool_execute_before`, then the tool or command itself, then `tool_execute_after`, then `session_end`. A hook that denies at `session_start` or `tool_execute_before` stops the invocation and the reason it gave is what you see. + + + + +Every other event name is accepted by the manifest but is **not dispatched yet**. A hook declared on one of them is valid, installs cleanly, and never runs. In particular, a hook does not fire around the tool calls the model makes during an ordinary interactive turn, so a hook cannot be used to police an interactive session today. Use [Permission policy](/cli/policy) for that. + + +## The events + +Names are written in the manifest in lower case with underscores. Listings elsewhere in the product print the same events in a dotted form, so `tool_execute_before` appears as `tool.execute.before`. The manifest only accepts the underscore form. + +| Event | Fires today | Subject | +| --- | --- | --- | +| `session_start` | yes | A session or a plugin invocation is starting | +| `session_end` | in `cortex plugin run` | The invocation finished, with its success or failure | +| `tool_execute_before` | in `cortex plugin run` | A tool is about to run, with its arguments | +| `tool_execute_after` | in `cortex plugin run` | A tool finished, with its success and output | +| `chat_message` | no | A message before it is sent | +| `permission_ask` | no | A permission question | +| `prompt_inject` | no | Adding to what the model is given | +| `ai_response_before`, `ai_response_stream`, `ai_response_after` | no | Around a model reply | +| `file_operation_before`, `file_operation_after`, `file_edited` | no | Around a file operation | +| `command_execute_before`, `command_execute_after` | no | Around a command | +| `error_handle` | no | An error being reported | +| `config_changed`, `model_changed`, `workspace_changed` | no | Something about the session changed | +| `clipboard_copy`, `clipboard_paste` | no | Clipboard activity | + +The manifest also accepts a set of interface-level events for extending the terminal interface itself. None of them are dispatched yet either, and they are not useful to target today. + +## Order and matching + +When several hooks listen for the same event, the order is deterministic: by `priority` first, lowest number first, then by plugin identity to break a tie. Two plugins that both ask for priority `50` will always run in the same order relative to each other, run after run. + +`pattern` decides whether a hook is offered the event at all: + +| Pattern | Matches | +| --- | --- | +| `*` | Everything | +| `*.rs` | Anything ending in `.rs` | +| `src/*` | Anything starting with `src/` | +| `read_file` | That subject exactly | + +One `*` at the start or the end is a prefix or suffix match. A pattern with no `*` is an exact match, not a substring search. + +## What a hook may not do + +A hook that fires before an action can change the payload it was given, and it can refuse the action outright with a reason. Both of those are bounded: + +- It cannot change which tool is being called, and it cannot remove the arguments. Trying to is refused with `A hook cannot change tool identity or remove arguments`. +- It cannot raise the role of a message. Trying to is refused with `Hooks cannot elevate message roles`. +- `tool_execute_after`, `session_end` and `error_handle` are observers. They see the outcome and can report on it, but they do not replace a result or reverse what already happened. + +## A hook is never consent + +A hook can say no. A hook can never say yes. + +Every permission question starts at "ask". A hook is allowed to answer "deny", and the first hook that answers anything other than "ask" settles it. If a hook answers "allow", the dispatch does not quietly accept it: the call fails with `Plugins cannot grant execution privileges`. A third-party plugin attempting it is refused with `Third-party plugins cannot auto-grant permissions (security restriction)`, and the engine checks the same thing again independently. + +So a hook cannot stand in for an approval, and it cannot remove one. If an action would have asked you, it still asks you. Wiring a hook in the hope of skipping a prompt does not work, by design and in two places. + +## When a plugin is not active + +Hooks are skipped for a plugin that is not loaded or has been disabled, quietly and without an error, which is what makes `cortex plugin disable` a complete off switch for that plugin's hooks. A plugin that is in any other non-active state reports `Plugin is not active` instead of being skipped. + +## The hooks file and the `/hooks` command + +Two things a reader often goes looking for are not available yet, and it is better to say so than to let you spend an afternoon on either. + +There is a configuration shape for standalone hooks, keyed by file pattern with a command, an environment and a timeout, and it is not read by anything in the shipped build. Writing that file has no effect. Hooks reach a session through a plugin manifest, as above. + +The `/hooks` command in the interactive interface is not wired either. Running it answers `Unsupported command in this session: hooks:list. No operation was performed.` Use `cortex plugin list` to see what is installed, and the plugin's own manifest to see which hooks it declares. + +## Related + +- [CLI plugins](/cli/plugins) - installing, trusting and building the plugin a hook belongs to. +- [Permission policy](/cli/policy) - the mechanism that does gate an interactive session. +- [Tools](/cli/tools) - the tools a `tool_execute_before` hook sees the name of. +- [Slash commands](/cli/slash-commands) - the commands that are wired in the interactive interface. +- [CLI troubleshooting](/cli/troubleshooting) - a declared hook that never runs. diff --git a/cli/hosts.mdx b/cli/hosts.mdx new file mode 100644 index 0000000..eabc5a3 --- /dev/null +++ b/cli/hosts.mdx @@ -0,0 +1,83 @@ +--- +title: "Cloud, This PC, and SSH" +description: "Where a CLI session runs its tools: Cortex Cloud by default, with This PC and SSH as opt-in hosts that fail closed" +icon: "server" +--- + +Every Cortex CLI session runs its tools somewhere. Reading a file, searching a directory, running a command, applying a patch: all of it happens on a **host**, and there are three. **Cloud** is the default and needs nothing from you. **This PC** and **SSH** are opt-in, selected with an environment variable, and they refuse a turn rather than quietly running it somewhere else. + +This page covers the three hosts and how to select one, what the two opt-in hosts require before they will accept a turn, the refusal you see when nothing is connected, how to hand a single turn to Cortex Cloud from the composer, and what the host setting does not control. + +## The three hosts + +| Host | Default | How you select it | +| --- | --- | --- | +| **Cloud** | Yes | Nothing to do | +| **This PC** | No | `CORTEX_COMPUTER=this_pc` | +| **SSH** | No | `CORTEX_SSH_HOST=`, or `CORTEX_COMPUTER=ssh` | + +The names on this page are the ones you use. `Computer` is the setting that chooses between them, and `CORTEX_COMPUTER` is the variable that carries it. + +## Cloud is the default + +The TUI and `cortex exec` create a Cloud session unless you explicitly select This PC or SSH. That is the shipped default, which is why a fresh install can complete a turn with no extra configuration at all. + +Cloud work runs in an isolated cloud environment that Cortex manages for you, not on your machine. Two things are worth separating in your head: the CLI never runs a model locally, so every turn goes to the coding service regardless of host, and the host only decides where the *tools* the model calls actually execute. + +## Select This PC + +Set `CORTEX_COMPUTER` to run tools on the machine you are sitting at: + +```bash +export CORTEX_COMPUTER=this_pc +cortex +``` + +The documented values are `this_pc` and `ssh`. Leaving the variable unset, or setting it to `cloud`, uses Cloud. The spellings `this-pc` and `local` are also accepted for This PC. + +This PC requires an **already connected Code session**. The connection itself is established on the Cortex Code side, not from the CLI, so the machine has to be set up there first. See [Runtimes](/code/runtimes) and [Machines](/code/machines). + +## Select an SSH host + +Set `CORTEX_SSH_HOST` to a target and the runtime becomes SSH: + +```bash +export CORTEX_SSH_HOST= +cortex +``` + +`CORTEX_SSH_TARGET` is an alias of the same variable. Setting either one selects SSH without touching `CORTEX_COMPUTER`, and the same connected-session rule applies: the host must already be connected to a Code session. See [SSH hosts](/code/ssh-hosts) for setting one up. + + +This PC and SSH are opt-in, and the CLI documentation describes them as possibly shipping during the 0.1.x series. If they are not enabled on your build, Cloud is the only host available to you. + + +## Both opt-in hosts fail closed + +There is no silent substitution. If This PC or SSH is selected and the host is not usable, the turn stops instead of running in Cloud. The refusal is a single message: + +``` +This PC and SSH Code execution require an already connected Code session +``` + +Read it as the whole story: connect the Code session, then run the turn again. A turn with nowhere to run stops and tells you that no host is connected rather than guessing. Cortex will not substitute Cloud on your behalf, because a command you meant to run on your own machine, against your own checkout, is not the same command anywhere else. + +If you are diagnosing a connection, do it from the Code side. That is where a host is attached to a session, and where its state is shown. + +## Hand one turn to Cortex Cloud + +You do not have to change the host to move a single turn. Type `&` at the start of the composer and that turn is handed to Cortex Cloud. The timeline records it as a row reading `↑ Handed off to Cortex Cloud`, so you can see afterwards which turns ran where. + +## What the host setting does not control + +`Computer` selects where tools run. That is all it does. In particular it is not browser or desktop control: the CLI ships no built-in browser or desktop-automation tool, and that kind of work is done by connecting a server that provides those tools, on whichever host the session is using. See [MCP servers in the CLI](/cli/mcp). + +The host also does not change the permission model. Approvals, the sandbox and the permission table apply identically on all three hosts, so selecting This PC does not widen what the agent may do, it only changes where it does it. + +## Related + +- [Tools the agent uses](/cli/tools), what the agent runs on the host you selected +- [Environment variables](/cli/environment-variables), `CORTEX_COMPUTER`, `CORTEX_SSH_HOST` and the rest +- [Modes and permissions](/cli/modes-and-permissions), the controls that apply on every host +- [Headless and one-shot runs](/cli/headless), choosing a host for an unattended run +- [Runtimes](/code/runtimes), how the same hosts appear in Cortex Code diff --git a/cli/index.mdx b/cli/index.mdx index bcca9c0..8ea1e8a 100644 --- a/cli/index.mdx +++ b/cli/index.mdx @@ -1,27 +1,39 @@ --- title: "Cortex CLI" -description: "Cortex Code in your terminal — an interactive session view, one-shot runs, headless mode for CI, and the extension points." -image: "/images/banners/code.png" -keywords: ["terminal", "command line", "cortex command"] +description: "Cortex Code in the terminal: an interactive session view, one-shot runs, headless runs for scripts, and every page of the CLI documentation" +icon: "terminal" --- -The Cortex CLI is **Cortex Code for the terminal**. One binary, `cortex`, gives you an interactive TUI with a live timeline and approvals, one-shot runs from your own shell, and a headless mode for scripts and CI. It uses the same account and the same Code sessions as the web and desktop apps, runs on the Cloud runtime by default, and never runs the model on your laptop. +The Cortex CLI is **Cortex Code in the terminal**. One binary gives you an interactive full-screen session view with a live timeline and approval prompts, one-shot runs from your own shell, and a headless mode for scripts. It uses the same Cortex account and the same Code sessions as the web and desktop apps, so a change you start in the terminal is the same piece of work you can pick up in a browser. - - Cortex CLI on a macOS desktop: splash, prompt, slash commands, and a Shell tool row - +One thing to know before anything else: **the CLI does not run a model on your machine**. Every turn goes to the Cortex coding service. When that service cannot be reached, the CLI says so and stops with a non-zero exit status; it never quietly substitutes something local. -## Install in one line +This page is the map of the CLI documentation. If you have never used it, follow the three Get started pages in order. - -```bash macOS and Linux -curl -fsSL https://software.cortex.foundation/install.sh | sh -``` +## Three ways to run it -```powershell Windows -irm https://software.cortex.foundation/install.ps1 | iex -``` - +| Surface | Command | Use it for | +| --- | --- | --- | +| Interactive session view | `cortex` | Everyday work: a timeline, approvals, Agent, Plan and Ask modes, sessions you can resume | +| One-shot | `cortex run "..."` | A single request from your shell, streamed, with session continuation | +| Headless | `cortex exec "..."` | Scripts and pipelines: an autonomy ceiling, machine-readable output, turn and time limits | + +## Install in one line + + + + ```bash + curl -fsSL https://software.cortex.foundation/install.sh | sh + ``` + + + ```powershell + irm https://software.cortex.foundation/install.ps1 | iex + ``` + + + +Then sign in and open a session in a project: ```bash cortex login @@ -29,77 +41,153 @@ cd ~/code/my-project cortex ``` -

- Install - Quickstart -

+## Get started - - Cortex CLI session composer with the pointer hovering over it - + + + The installers for macOS, Linux and Windows, what the checksum check proves, pinning a version, `cortex upgrade`, uninstalling. + + + `cortex login` in a browser, a device code for machines without one, single sign-on, API keys for unattended runs. + + + Install, sign in, a first turn in a project, `AGENTS.md`, and how much autonomy to grant on day one. + + -## What one binary gives you +## Use the CLI -| Surface | Command | Use it for | -| --- | --- | --- | -| **Interactive TUI** | `cortex` | Everyday work: a timeline, approvals, Agent / Plan / Ask, sessions you can resume, rewind, and fork | -| **One-shot** | `cortex run "…"` | A single request from your shell, streamed, with session continuation and sharing | -| **Headless** | `cortex exec "…"` | Scripts and CI: autonomy levels, JSON output, turn and time limits | + + + Everything on screen: the timeline, the composer and its chips, the footer hints, queueing a follow-up, the panels. + + + Agent, Plan, Ask and Bash, the approval prompt, the sandbox, and the permission table. + + + Get a plan before anything changes, accept or keep iterating, and the stricter Spec lock. + + + Sessions are files: list, resume, rewind, fork, export, import, share, lock and clean up. + + + A long-horizon objective that survives compaction and resume, with a turn budget and evidence. + + + Everything after `/` in the composer, grouped by purpose, plus your own custom commands. + + + Every binding, grouped by where it applies, and the in-app shortcuts overlay. + + + Search, read, edit, shell and the rest, how each one appears in the timeline, and which ones ask first. + + + Where a session actually runs, how to opt in to the other hosts, and why they fail closed. + + + Driving the CLI from an editor over the agent protocol, and what is not wired yet. + + -## Guides +## Automate - - Installer, checksums, version pins, channels, `cortex upgrade`, uninstall. + + `cortex run` and `cortex exec`: autonomy levels, output formats, turn and time limits, exit codes. - - `cortex login` in a browser, device code for headless machines, API keys for CI, the OS keyring. + + Recipes for pipelines: the key in the environment, parsing the result document, reviewing uncommitted changes. - - First session, `AGENTS.md`, choosing autonomy. + + +## Configure + + + + `config.toml` keys, profiles, and the five layers that decide which value wins. - - Timeline rows, the composer, status line, queueing follow-ups, interrupting. + + Every `CORTEX_*` variable the CLI reads and what each one overrides. - - Everything after `/` — model, mode, permissions, plan, goal, sessions, MCP, diagnostics. + + Where sessions, configuration, cache and credentials live on each operating system. - - Agent / Plan / Ask, Spec, approvals, sandbox, the `permission` table, effort. + + Allow and deny rules for tools and commands, and the managed policy an organization can set. - - `/goal` — a persisted long-horizon objective that survives compaction and resume. + + +## Extend + + + + Add a server, the supported transports, authentication, tool naming, and the connection panel. - - Resume, rewind, fork, export, import, share, lock, clean up. + + Skill files, where the CLI looks for them, how the agent picks one, and writing your own. - - Every binding, grouped by where it applies — plus the Ctrl+X overlay. + + Custom agents, their tool access, and when the CLI delegates part of a turn. + + + The hooks block in a plugin manifest, which events actually fire, and why a hook can refuse but never approve. - - `cortex exec` and `cortex run` in scripts, GitHub Actions, GitLab CI. + + Installing and enabling plugins, the sandbox they run in, and the development workflow. - - `config.toml`, profiles, environment variables, data locations, hosts. + + The built-in themes, switching them, and the related display settings. - - MCP servers, skills, agents and subagents, hooks, plugins, themes. + + +## Reference + + + + Every `cortex` subcommand and flag, one table per command group. - - Outage copy, hosts that refuse, the agent that will not edit, MCP, quotas. + + The diagnostic commands first, then the messages you might see and what to do about each. +## How it fits with the other products + +Cortex Code is the same product in a browser and on the desktop. The terminal is another front end onto it, not a separate service. + +| In Code | In the CLI | +| --- | --- | +| A session on a repository | Change into the project directory and run `cortex`; the CLI reuses that workspace's Code session, so turns continue the same session | +| Ask, Plan and Agent | Press **Shift+Tab** to cycle Agent, Plan and Ask | +| Stop | Press **Esc**; the timeline shows `Stopped` | +| The Cloud host | The default for the session view and for `cortex exec` | +| This PC and SSH | Opt in per session, and only with an already connected Code session | +| Approvals | A numbered prompt in the composer before anything consequential | +| Model choice | The model chip at the bottom right of the composer, and the model picker | + +| The CLI does | The CLI does not | +| --- | --- | +| Drive Code sessions from a terminal | Run a model on your own machine | +| Work in a project directory | Replace Cortex Chat | +| Offer This PC and SSH hosts | Put those hosts in the browser | +| Extend with MCP servers, skills, agents, hooks and plugins | Manage Cortex Bot or Cortex Design | + ## 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. -- Everything documented here is backed by the shipped CLI. `cortex --help` and `cortex --help` are generated from the same definitions and are always authoritative. -- The CLI talks to the Cortex API at `api.cortex.foundation`. Releases are published to `software.cortex.foundation`. -- Source and issues: [github.com/CortexLM/cli](https://github.com/CortexLM/cli), Apache-2.0. +- Commands are written as `cortex ...`. The installed binary file is named `Cortex`, and the command you type is `cortex`. +- The generated help is always authoritative: `cortex --help` and `cortex --help` come from the same definitions as the shipped commands. If this documentation and the help output ever disagree, believe the help. +- The CLI talks to the Cortex API over HTTPS at `api.cortex.foundation`. Releases are published to `software.cortex.foundation`. +- Source and issues: [github.com/CortexLM/cli](https://github.com/CortexLM/cli), licensed Apache-2.0. + + +Version numbers move between releases, so no page here pins one. Run `cortex --version` to see what you have, and `cortex upgrade --check` to see what is published on your channel. + -## Next +## Related -1. [Install the CLI](/cli/install) — checksums, version pins, and channels. -2. [Sign in](/cli/sign-in) — the browser flow, device codes, and CI keys. -3. [CLI quickstart](/cli/quickstart) — a working Code session in the terminal. -4. [Modes and permissions](/cli/modes-and-permissions) — decide how much the agent may do. +- [Install the CLI](/cli/install) +- [Sign in](/cli/sign-in) +- [CLI quickstart](/cli/quickstart) +- [Cortex Code](/code/index) and [Code in the terminal](/code/cli) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/install.mdx b/cli/install.mdx index 2754c66..01517fa 100644 --- a/cli/install.mdx +++ b/cli/install.mdx @@ -1,99 +1,130 @@ --- title: "Install the CLI" -description: "Install Cortex CLI on macOS, Linux, or Windows. The installer verifies a SHA-256 checksum before it writes anything; cortex upgrade keeps it current." -keywords: ["setup", "download", "upgrade", "update", "checksum"] +description: "Install Cortex CLI on macOS, Linux or Windows, pin a version or a channel, keep it current with cortex upgrade, and uninstall it cleanly" +icon: "download" --- -The installer downloads the release build for your platform from [software.cortex.foundation](https://software.cortex.foundation), verifies its SHA-256 checksum against the release manifest, and installs the binary. Nothing is written until the checksum matches. +Cortex CLI installs as a single binary. An install script fetches the release build for your platform from `software.cortex.foundation`, verifies its SHA-256 checksum against the release manifest, and only then writes anything to disk. There is nothing to configure afterwards: sign in and you have a working session view. - - Cortex CLI welcome splash for v0.1.10 with the empty composer - +This page covers the installers for macOS, Linux and Windows, what the checksum check does and does not prove, how to pin a version or a release channel, keeping the CLI current with `cortex upgrade`, building from source, and uninstalling. -## macOS and Linux +## Install -```bash -curl -fsSL https://software.cortex.foundation/install.sh | sh -``` + + + ```bash + curl -fsSL https://software.cortex.foundation/install.sh | sh + ``` + + This installs the binary into `~/.local/bin` and puts a `cortex` command there. Add that directory to your `PATH` yourself if it is not already on it. The install script needs Python 3.8 or later. + + + ```powershell + irm https://software.cortex.foundation/install.ps1 | iex + ``` -Installs `Cortex` into `~/.local/bin`, plus `cortex` and `agent` symlinks. Add that directory to your `PATH` if it is not there already. Python 3.8 or later is required by the installer. + This installs into `%LOCALAPPDATA%\Cortex\bin`. Add that folder to your user `PATH` yourself; the installer does not edit your profile or your `PATH`. -Prefer to read the script first: + Windows x64 only. Native ARM64 and 32-bit builds are not published, and the installer does not silently substitute another architecture. + + + + +If you would rather read the script before you run it, fetch it into a pager first: ```bash curl -fsSL https://software.cortex.foundation/install.sh | less ``` + + +Confirm the result: + +```bash +cortex --version +``` -What the installer does and refuses to do: +## What the installer does, and refuses to do | Behaviour | Detail | | --- | --- | -| Selects the right asset | GNU or musl Linux for x86_64 and AArch64; macOS for Intel and Apple silicon | -| Fails closed | Unknown architectures, unknown libc, or a missing platform asset stop the install | -| Bounded downloads | Redirects are rejected; extraction accepts only the release binary | -| Protects your `bin` | Refuses to overwrite unrelated commands or binary symlinks | -| Keeps a recovery copy | An existing binary is kept as `Cortex.old`; a failed post-install check restores it | +| Selects the right build | GNU or musl Linux on x86_64 and AArch64; macOS on Intel and Apple silicon | +| Fails closed | An unknown architecture, an unknown libc, or a missing platform asset stops the install rather than guessing | +| Bounded downloads | Redirects are rejected, and archive extraction accepts only the release binary | +| Protects your bin directory | It refuses to overwrite an unrelated command of the same name, or a binary symlink | +| Keeps a recovery copy | An existing binary is kept as `Cortex.old`, or `Cortex.old.exe` on Windows | -### Options + +Minimum operating system, kernel and libc versions are not published. The musl builds have audio disabled and must pass a static-link check, but that does not establish a supported floor for any platform. + -| Variable | Effect | -| --- | --- | -| `CORTEX_VERSION=0.1.8` | Pin a version, for example `curl … \| CORTEX_VERSION=0.1.8 sh` | -| `CORTEX_INSTALL_DIR=…` | Change the prefix; the binary goes in its `bin` | -| `CORTEX_CHANNEL=stable\|beta\|nightly` | Pick a release channel | +## What the checksum check proves -## Windows +The install script verifies the SHA-256 checksum of the archive against the release manifest before it writes anything, and `cortex upgrade` verifies it again before replacing a binary. The check happens for you; there is no separate command for verifying a download by hand. -```powershell -irm https://software.cortex.foundation/install.ps1 | iex -``` + +Checksums detect corruption, not publisher identity. The SHA-256 values come from the same distribution origin as the archive, so a match tells you the download arrived intact, not who produced it. **Checksums are not signatures.** There is no release signing, notarization, provenance attestation, or software bill of materials behind these downloads, and nothing here should be read as one. + + +## Pin a version, or change the channel -Installs into `%LOCALAPPDATA%\Cortex\bin` after the same checksum check. Add that folder to your user `PATH` yourself — the installer does not edit your profile. Windows x64 only; ARM64 and 32-bit builds are not published, and the installer does not silently substitute another architecture. An existing binary is kept as `Cortex.old.exe`. +Set these in the environment of the shell that runs the install script. -## Check it worked +| Variable | Effect | +| --- | --- | +| `CORTEX_VERSION` | Pin a specific release instead of taking the newest one | +| `CORTEX_INSTALL_DIR` | Change the install prefix; the executable lands in that prefix's `bin` | +| `CORTEX_CHANNEL` | Pick a release channel: `stable`, `beta` or `nightly` | ```bash -cortex --version +curl -fsSL https://software.cortex.foundation/install.sh | CORTEX_VERSION=0.1.8 sh ``` -## Update +## Keep it current ```bash -cortex upgrade # latest on your channel -cortex upgrade --check # report only +cortex upgrade # newest release on your channel +cortex upgrade --check # report what is available, install nothing cortex upgrade 0.1.10 # a specific version ``` -`cortex upgrade` fetches the release manifest from `software.cortex.foundation`, verifies SHA-256 before replacing the binary, keeps a `.old` recovery copy, and checks the new binary's `--version` before finishing. A lookup failure returns a non-zero exit status — an unavailable release is never reported as already installed. Installations made through a package manager are directed back to that package manager. - -The TUI also offers `/upgrade`, and `check_for_update_on_startup` in [configuration](/cli/configuration) controls the launch-time check. +The full flag set is `-c/--check`, `--changelog`, `-f/--force`, `-y/--yes`, `--channel` and `--pre`. Version pins follow SemVer ordering, including prereleases. From inside a session, `/upgrade` does the same thing, and the `check_for_update_on_startup` key in [configuration](/cli/configuration) controls the check at launch. -## Homebrew and WinGet +An upgrade verifies SHA-256 before it replaces anything, keeps the previous binary beside the new one as a recovery copy, then runs the new binary's `--version` with a deadline and bounded output. If that check fails, the previous binary is restored. A failed release lookup exits non-zero rather than reporting that you are already up to date. -The release pipeline publishes assets that a Homebrew formula in `CortexLM/homebrew-tap` and a WinGet package `CortexLM.Cortex` reference. Coverage varies by platform; the shell and PowerShell installers above are the supported path. + +If you installed through a package manager, `cortex upgrade` sends you back to that package manager instead of replacing the binary itself. Automatic replacement of a musl installation is also refused: use the install script above for those. Package-manager coverage varies by platform and is not documented here; the shell and PowerShell installers are the supported path. + ## Build from source +This is contributor scope, not the supported way to install the CLI. Use the Rust toolchain version pinned in the repository. + ```bash -# Linux only: headers for the optional audio/desktop crates +# Linux only: headers for the optional audio and desktop crates sudo apt-get install -y libasound2-dev pkg-config cargo build -p cortex-cli --release -# binary: target/release/Cortex +# the binary lands at target/release/Cortex ``` -Use the Rust toolchain pinned in the repository's `rust-toolchain.toml`. +Source and issues live at [github.com/CortexLM/cli](https://github.com/CortexLM/cli), licensed Apache-2.0. ## Uninstall ```bash -cortex uninstall --dry-run # show what would be removed -cortex uninstall # remove the binary and data -cortex uninstall --keep-config --keep-data -cortex uninstall --backup # archive data first +cortex uninstall --dry-run # show what would be removed +cortex uninstall # remove the binary and its data +cortex uninstall --keep-config --keep-data # leave your settings and sessions +cortex uninstall --backup # archive the data first ``` -## Next +The full flag set is `-c/--keep-config`, `-d/--keep-data`, `--dry-run`, `-f/--force`, `-y/--yes`, `--backup` and `-p/--purge`. To see what would be deleted before you commit to it, check [Data locations](/cli/data-locations). + +## Related -- [Sign in](/cli/sign-in) — `cortex login`. -- [Quickstart](/cli/quickstart) — a first session. +- [Sign in](/cli/sign-in) +- [CLI quickstart](/cli/quickstart) +- [Configuration](/cli/configuration) +- [Data locations](/cli/data-locations) +- [CLI troubleshooting](/cli/troubleshooting) +- [Downloads](/getting-started/downloads) diff --git a/cli/keyboard.mdx b/cli/keyboard.mdx index d3fe21f..c30d5c0 100644 --- a/cli/keyboard.mdx +++ b/cli/keyboard.mdx @@ -1,114 +1,130 @@ --- -title: "Keyboard shortcuts" -description: "Every key binding in the Cortex CLI, grouped by where it applies. Press Ctrl+X in the TUI for the in-app overlay, or ? for help." -keywords: ["shortcuts", "keybindings", "hotkeys"] +title: "CLI keyboard shortcuts" +sidebarTitle: "Keyboard shortcuts" +description: "The key bindings in the Cortex CLI, grouped by where they apply: global, the composer, a running turn, the approval prompt, and the dialogs" +icon: "keyboard" --- -Press **Ctrl+X** at any time for the shortcuts overlay, or **?** / **F1** for help. The footer always shows one hint for the current context. +The terminal app is meant to be driven from the keyboard. A handful of keys cover almost everything: `Shift+Tab` to change what the agent is allowed to do, `Enter` to send or to queue, `Esc` to interrupt or to close, `F2` for settings, and four sigils that open a picker instead of typing text. Everything else is a slash command. - - Cortex CLI shortcuts overlay listing the key bindings - +This page groups the bindings by where they apply, because the same key does different things depending on what has focus. It also points out the two places where the sources disagree with each other, so you know to trust the footer strip on your own screen rather than a table on a page. + +## The shortcuts sheet in the app + +Type `/shortcuts` (alias `keys`) to open the sheet. It is a compact overlay listing the current bindings, with a footer line that reads `Docs & guides: cortex.foundation/docs` followed by the version you are running. `Esc` closes it. + + +The footer strip draws `Ctrl+x:shortcuts`, but in the current build `Ctrl+x` clears the queued follow-ups instead of opening the sheet. Until that is settled, open the sheet with `/shortcuts`. + ## Global | Key | Action | | --- | --- | -| **Shift+Tab** | Cycle the mode — Agent → Plan → Ask | -| **Ctrl+K** or **Ctrl+P** | Command palette | -| **Ctrl+X** | Shortcuts overlay | -| **F2** | Settings | -| **?** or **F1** | Help | -| **Esc** | Cancel or close; interrupt a running turn | -| **Esc**, **Esc** (quickly) | Rewind overlay | -| **Tab** | Focus the next element | -| **Ctrl+I** | Focus the composer | -| **Ctrl+B** | Toggle the sidebar | -| **Ctrl+N** | New session | -| **Ctrl+S** or **Ctrl+O** | Sessions | -| **Ctrl+M** | Model picker | -| **Ctrl+E** | MCP servers | -| **Ctrl+T** | Transcript | -| **Ctrl+Q** | Quit | -| **Ctrl+C** | Copy the selection; force-quit while a turn runs | -| **Ctrl+Shift+C** / **Ctrl+Shift+V** | Copy / paste | +| `Shift+Tab` | Cycle the mode: Agent, then Plan, then Ask | +| `F2` | Open Settings | +| `Esc` | Interrupt a running turn, close a panel, or leave Bash mode | +| `Ctrl+p` | Open the command palette | +| `Ctrl+r` | Search past sessions | +| `Ctrl+Shift+C` | Copy | +| `Ctrl+Shift+V` | Paste | +| `Ctrl+Q` | Quit, the same as `/quit` | + +`Ctrl+c` is described both as stop and as force-quit in the sources, so treat it as the abrupt option: use `Esc` to interrupt a turn and `Ctrl+Q` or `/quit` to leave cleanly. ## Composer | Key | Action | | --- | --- | -| **Enter** | Send | -| **Shift+Enter** or **Alt+Enter** | Insert a newline | -| **Up** / **Down** | Previous / next prompt in history | -| **Ctrl+U** or **Ctrl+L** | Clear the composer | -| **Ctrl+V** | Paste | -| **Ctrl+A** | Select all | -| `/` | Slash command list | -| `@` | File or symbol reference | -| `!` | Run a shell command | +| `Enter` | Send the message, or queue it while a turn runs | +| `Alt+Enter` | Insert a newline | +| `↑` | Edit your last message, or edit a message already in the queue | +| `Tab` | Complete a slash command | +| `/` | Open the command list | +| `@` | Open the file picker | +| `!` | Enter Bash mode, where what you type runs in your shell | +| `&` | Hand the task off to Cortex Cloud | -## Timeline +The four sigils only open something when they start a line. Inside a sentence they are ordinary characters. In Bash mode the prompt sigil changes from `>` to `!`, and `Esc` leaves it. -Applies when the transcript has focus. +## While a turn is running | Key | Action | | --- | --- | -| **j** / **k**, **Down** / **Up** | Scroll | -| **g** / **Shift+G** | Top / bottom | -| **Home** / **End** | Top / bottom | -| **PageUp** / **PageDown** | Page | -| **Ctrl+U** / **Ctrl+D** | Half page | -| **e** | Expand or collapse tool details | -| **y** | Copy the selection | -| **p** | Paste | +| `Esc` | Interrupt the turn. The timeline records `× Stopped` | +| `Enter` | Queue what you typed as a follow-up instead of sending it now | +| `↑` | Edit a queued message | -## Pickers and prompts +Queueing is the normal way to work: you do not have to wait for the agent to finish before writing the next instruction. -Approvals, `/mode`, `/permissions`, `/model`, plan confirmation, and questions are numbered pickers. The mouse works on them too: hover a row to highlight it, click to choose. +## Approval prompt - - Cortex CLI approval prompt with the pointer hovering over an option - +When the agent wants to run something that needs your say-so, a numbered prompt appears inline in the timeline and the composer waits for you. | Key | Action | | --- | --- | -| **↑** / **↓** or **k** / **j** | Move the selection | -| **1** – **9** | Choose an option by number | -| **Enter** | Confirm | -| **Tab** | In `/model`, cycle the effort radios | -| **e** | In an approval, edit the command | -| **Esc** | Cancel — or clear the search box first | +| `↑` and `↓` | Move the selection | +| `1` to `9` | Choose an option by its number | +| `Enter` | Confirm the selected option | +| `e` | Edit the command before it runs | +| `Esc` | Cancel | -In the theme picker, moving the selection previews the theme live and **Esc** reverts. +Its footer strip is drawn exactly like this, and the same four keys apply to any numbered prompt: -## Sessions panel +``` + ↑↓:select | Enter:confirm | e:edit command | Esc:cancel +``` + +What each numbered option means, including what *always allow* remembers, is on [Modes and permissions](/cli/modes-and-permissions). + +## Model and effort lists | Key | Action | | --- | --- | -| **Enter** | Resume the selected session | -| **f** | Favourite | -| **d** or **Delete** | Delete | -| **r** or **F2** | Rename | -| **e** | Export | +| `Enter` | Choose the highlighted model, or apply the effort | +| `Tab` | Move from the model list to the reasoning-effort list, and back | +| `↑` and `↓` | Move the selection | +| `Esc` | Close the list | + +## Settings and other dialogs -## Rewind overlay +Settings and the pickers share one navigation style, and it accepts both arrows and vim-style keys. | Key | Action | | --- | --- | -| **←** / **→** | Move between points in the conversation | -| **Enter** | Roll back to the selected point | -| **f** | Fork a new session from it | -| **Esc** | Cancel | +| `↑` and `↓`, or `j` and `k` | Move | +| `g` and `G` | Jump to the top or the bottom | +| `Space` or `Enter` | Toggle the selected row | +| `→` | Expand a submenu | +| `/` | Search inside Settings | +| `d` | Reset the selected row to its default | +| `F2` or `Esc` | Close | -## Resume picker (startup) +`j`, `k`, `g` and `G` are a navigation style inside these panels. There is no vim mode in the CLI and no command that turns one on. -| Key | Action | +## Sessions, resume and rewind + +| Key or command | Action | | --- | --- | -| **Enter** | Resume the selected session | -| **F** | Fork from it | -| **N** or **Esc** | Start a new session | +| `Ctrl+r` | Search past sessions | +| `f` | Toggle the favourite mark on the selected row in the sessions panel | +| `/resume` | Open the resume picker | +| `Esc` `Esc` in quick succession | Open the rewind overlay | + + +The resume picker is the one screen where the sources give two different key maps, one with favourite and delete and one with fork and new session. Read the footer strip on your own screen for that panel rather than trusting a table. Everything the picker does is also available as a slash command: `/resume`, `/fork`, `/favorite`, `/delete`. + + +## The footer strip is the live answer + +The strip along the bottom of the screen changes with what is in focus: idle, text typed, a narrow terminal, a turn running, the queue, the model list, the effort list, an approval prompt, the MCP panel, the plugins panel, the resume picker and Bash mode all have their own. Each strip shows the keys that apply at that moment, in the form `key:label` separated by vertical bars, and hovering a chunk highlights it. + +The strips are deliberately short, so a strip is not the complete list of bindings for that screen, and the set of strips is still growing. When a key you expect is missing, check the strip first and the shortcuts sheet second. ## Related -- [The TUI](/cli/tui) · [Slash commands](/cli/slash-commands) -- [Web app shortcuts](/getting-started/settings#keyboard-shortcuts) +- [The TUI](/cli/tui): the regions of the screen these keys act on +- [Slash commands](/cli/slash-commands): everything reachable by typing `/` +- [Modes and permissions](/cli/modes-and-permissions): what `Shift+Tab` and the approval prompt decide +- [CLI sessions](/cli/sessions): resume, fork and rewind in detail +- [Themes](/cli/themes): the Settings rows behind `F2` diff --git a/cli/mcp.mdx b/cli/mcp.mdx new file mode 100644 index 0000000..446c586 --- /dev/null +++ b/cli/mcp.mdx @@ -0,0 +1,170 @@ +--- +title: "MCP servers in the CLI" +sidebarTitle: "MCP servers" +description: "Connect Model Context Protocol servers to the CLI: the three transports, tokens, tool names, permissions, and the server panel" +icon: "server" +--- + +The Cortex CLI is a Model Context Protocol client. Connecting an MCP server adds its tools to the set the agent can call, alongside the built-in tools. That is how you give a session a capability the CLI does not ship with: the agent sees the server's tools as ordinary tools, and every one of them passes the same approval and sandbox boundary as a built-in tool. + +This page covers adding a server over each of the three transports, how tokens are handled, the commands for listing, enabling and removing servers, how to diagnose one that will not connect, how the server's tools are named and how to control them, and where the configuration ends up on disk. + +## Add a server + + + + The CLI launches the server itself and talks to it over standard input and output. Everything after `--` is the command Cortex launches: + + ```bash + cortex mcp add myserver -- npx @example/mcp-server + cortex mcp add myserver -- python -m my_server + cortex mcp add myserver --env API_HOST= -- node server.js -v + ``` + + + For a server that speaks streamable HTTP, give it a URL: + + ```bash + cortex mcp add myapi --url https:///mcp + cortex mcp add myapi --url https:///mcp --bearer-token-env-var MY_API_TOKEN + ``` + + `--bearer-token-env-var` takes the **name** of an environment variable. Cortex reads the token from it at runtime, so the token itself never lands in a config file. + + + For a server that streams events: + + ```bash + cortex mcp add myevents --sse https:///sse + cortex mcp add myevents --sse https:///sse --sse-bearer-token-env-var MY_API_TOKEN + ``` + + + + +The `--` matters. Without it, flags meant for the server (`-v`, `-m`) are parsed as Cortex flags. + + +URLs pointing at `localhost`, `127.0.0.1` or private network ranges are rejected by default. Pass `--allow-local` when you are deliberately talking to a development server. + + +A server you add is code you have chosen to run, and its tools act with the authority the session gives them. Nothing establishes who published a server. The CLI verifies a SHA-256 checksum for its own release downloads, and even there a checksum detects corruption, not independent publisher identity: checksums are not signatures. + + +## Manage servers + +```bash +cortex mcp list # alias: ls +cortex mcp list --all # include disabled servers +cortex mcp list --json +cortex mcp get +cortex mcp enable +cortex mcp disable +cortex mcp rename +cortex mcp remove # alias: rm +``` + +Inside a session, `/mcp` opens the manager, `/mcp-tools` lists the tools each server exposes, and `/mcp-reload` re-reads the configuration after you have edited it. `Ctrl+E` opens the manager directly. + +## Sign in to a server that requires it + +Some servers will not expose their tools until you have authorised the CLI with them: + +```bash +cortex mcp auth +cortex mcp auth list +cortex mcp logout +cortex mcp logout --all +``` + +`/mcp-auth` covers the same ground without leaving the session. + +## Diagnose a server that will not connect + +```bash +cortex mcp debug +cortex mcp debug --test-auth +cortex mcp debug --timeout 60 --no-cache +cortex mcp debug --json +``` + +## Read the server panel + +The panel header counts what is live, for example `MCP servers · 2 of 4 connected`. Each row is the server name, its tool count, and its state. A connected row is prefixed with a tick and reads ` 12 tools · connected`, with the count coming from the server itself. The other states look like this: + +``` +⠇ authenticating… +× failed — token expired · r to reconnect +``` + +A row still in progress shows a braille spinner and the word `authenticating…`. A failed row is marked with `×` and carries the reason and the recovery key inline. A row with no glyph has not been attempted, and the selected row is prefixed `> `. `token expired` is one reason among others, so read the row rather than assuming the cause. + +The footer strip on that panel is: + +``` + Enter:details | r:reconnect | a:add server | Esc:close +``` + +## Tool names and permissions + +A tool from server `myserver` called `search` is presented as `mcp__myserver__search`. That prefix is what you use when filtering with `--enabled-tools` or `--disabled-tools`, and what appears in the `permission.mcp` table: + +```toml +[permission.mcp] +"myserver" = "allow" +"risky-server" = "ask" +``` + +Entries take `allow`, `ask` or `deny`, like the rest of the permission table. See [Permission policy](/cli/policy) for how those rules combine with the approval policy and the sandbox, and [Tools the agent uses](/cli/tools) for the built-in names. + +MCP is also how browser work gets done: Cortex ships no built-in browser or desktop-automation tool. Connect a server that provides those tools, and they pass the same boundary as any other tool call. `/browser` reports whether such a server is connected and names it. + +## Where the configuration lives + +`cortex mcp add` writes into the global `config.toml` under `mcp_servers`: + +```toml +[mcp_servers.myserver] +enabled = true + +[mcp_servers.myserver.transport] +type = "stdio" +command = "npx" +args = ["@example/mcp-server"] + +[mcp_servers.myserver.transport.env] +API_HOST = "internal" +``` + +```toml +[mcp_servers.myapi] +enabled = true + +[mcp_servers.myapi.transport] +type = "http" +url = "https:///mcp" +bearer_token_env_var = "MY_API_TOKEN" +``` + +```toml +[mcp_servers.myevents] +enabled = true + +[mcp_servers.myevents.transport] +type = "sse" +url = "https:///sse" +``` + +`type` is one of `stdio`, `http`, `sse` or `web_socket`, and `enabled` defaults to `true`. There is no `cortex mcp add` flag for `web_socket`; it is configuration only. + +Servers you add from inside the session are stored separately, as one file per server in the CLI's own data directory rather than in `config.toml`. So a server that `cortex mcp list` shows but `config.toml` does not mention was almost certainly added that way. See [Data locations](/cli/data-locations). + +The sources describe MCP servers as a source of **tools**. Whether a server can also contribute prompts or resources to a session is not established, and no limit on the number of servers or tools is published. + +## Related + +- [Tools the agent uses](/cli/tools) +- [Permission policy](/cli/policy) +- [CLI plugins](/cli/plugins) +- [Configuration](/cli/configuration) +- [Data locations](/cli/data-locations) diff --git a/cli/modes-and-permissions.mdx b/cli/modes-and-permissions.mdx index e7a6f56..cab29b8 100644 --- a/cli/modes-and-permissions.mdx +++ b/cli/modes-and-permissions.mdx @@ -1,89 +1,118 @@ --- title: "Modes and permissions" -description: "Agent / Plan / Ask, the Spec lock, approval prompts, the sandbox, the permission table, and the model picker's effort radios." -keywords: ["Agent", "Plan", "Ask", "sandbox", "approvals", "autonomy"] +description: "The four composer modes, the approval prompt, the sandbox, the permission table, and the reasoning-effort options" +icon: "sliders" --- -Every CLI session runs under three controls: a **mode** that decides which tools the model is even offered, an **approval policy** that decides when you are asked, and a **sandbox** that decides what a tool may touch when it runs. Effort, on the model picker, decides how hard the model thinks. +Every CLI session runs under three separate controls. A **mode** decides which tools the agent is offered at all. An **approval policy** decides when you are asked before a tool acts. A **sandbox** decides what a tool may touch once it does run. Reasoning **effort**, set beside the model, decides how hard the model thinks about the request. -## Modes: Agent, Plan, Ask +This page covers the four composer modes and how to switch them, what the approval prompt looks like and what each option commits you to, the sandbox and the prompt you get when it blocks something, the per-capability permission table in `config.toml`, the model and effort lists, and which control to reach for in a given situation. -**Shift+Tab** cycles them; `/mode` opens the picker. The footer shows the current one. +## The four modes -| Mode | The agent may | Use it for | -| --- | --- | --- | -| **Agent** | Read, write, and run commands | The change you have decided on | -| **Plan** | Read and propose. No writes, no commands. | Working out *what* to do before anything moves | -| **Ask** | Read and explain | Understanding code | +`Shift+Tab` cycles Agent, Plan and Ask. The mode chip on the top border of the composer always names the current one, verbatim: -Plan and Ask are **harness locks**: the mutating tools are withheld, not merely discouraged. In Plan mode the composer border reads *Plan · no edits* and the agent drafts a plan first. +| Mode | Chip | The agent may | Use it for | +| --- | --- | --- | --- | +| Agent | `Agent` | Read, write, and run commands | The change you have already decided on | +| Plan | `Plan · no edits` | Read and propose, nothing else | Working out what to do before anything moves | +| Ask | `Ask · read-only` | Read and explain | Understanding code | +| Bash | `Bash · runs in your shell` | Nothing. You are the one running commands | A quick command without leaving the session | - - Cortex CLI in Plan mode showing a drafted plan and the Plan · no edits composer - +Bash mode is not part of the cycle: type `!` at the start of the composer to enter it, and `Esc` to leave. While you are in it the composer sigil changes from `>` to `!`, and what you type runs in your shell rather than going to the agent. -When a plan is ready, the TUI asks whether to implement it — **Yes, switch to Agent mode and implement**, or **No, keep planning**: +Plan and Ask are **locks, not suggestions**. The mutating tools are withheld by the agent harness, so the agent cannot write a file or run a mutating command even if it decides it should. Plan mode has a page of its own: [Plan and Spec modes](/cli/plan-mode). The same three modes exist in the web app as Ask, Plan and Agent, see [Ask, Plan, Agent](/code/interactions). - - Cortex CLI plan confirmation picker with two numbered options - +## Approve or refuse a command -The same three modes exist in web Code as Ask / Plan / Agent — see [Ask, Plan, Agent](/code/interactions). +When the agent wants to do something consequential in Agent mode, the prompt appears inline in the timeline and the composer waits: -## Spec mode +``` +● Cortex wants to run + 1 Yes, run once + 2 Yes, always allow npm install in this project + 3 Edit command + 4 No — tell Cortex what to do instead +``` + +`↑` and `↓` move the selection, `Enter` confirms, `1` to `9` pick a numbered option directly, `e` edits the command before it runs, and `Esc` cancels. + +Option 2 is the one to read carefully. It is templated on the **kind** of command, not on the exact string, so choosing *always allow ... in this project* remembers that family of command for this project rather than every command everywhere. -`/spec` goes a step further than Plan. The agent produces a **structured plan** — title, description, tasks with a complexity rating, architecture, risks, success criteria — and the mutating tools stay locked until you accept it. Leave with `/spec off`. Headless runs can start in it with `cortex exec --use-spec`, optionally with `--spec-model ` for the planning pass. +## When the sandbox blocks something -Why it exists: you see the shape of the work while it is still cheap to redirect, the plan is an artefact you can paste into an issue, and the block on mutating tools is enforced by the harness rather than by asking the model nicely. +The sandbox is the second gate, and it applies whether or not you were asked for approval: it decides what an operation is physically allowed to touch. When it blocks one, the timeline says so and offers three ways forward: **Keep blocked**, **Allow once**, or **Allow for this session**. -## Approvals +Approval and sandboxing are independent. A command can be approved by you and still be refused by the sandbox, which is the point: approval is about intent, the sandbox is about reach. -When the agent wants to run something consequential, the prompt appears inline under the command and the composer waits. There is one approval path: numbered options — run once, always allow this kind of command in this project, edit the command first, or decline and say what to do instead. +## Set the policy for a session - - Cortex CLI inline approval prompt with four numbered options - +From the composer: -`/permissions` sets the policy for the session: +- `/approval` takes one of `ask`, `session`, `always` or `never`. +- `/sandbox` turns sandboxed execution on or off. +- `/auto` turns auto-approval on or off. -| Policy | Meaning | +The same policy is also offered as three named presets in the session's autonomy picker: + +| Preset | What it means | | --- | --- | -| **Smart** | Auto-approve safe reads, ask before edits and commands (the default) | -| **Read-only** | Never edit files or run commands | -| **Full access** | Only ask when leaving the sandbox | +| **Smart** | Auto-approve safe reads, ask before edits and commands. The default | +| **Read-only** | Never edit files, never run commands | +| **Full access** | Only ask when something leaves the sandbox | - - Cortex CLI /permissions picker with Smart, Read-only, and Full access - +## From the command line -From the command line the same thing is `--ask-for-approval `; `on-request` is the default. `/approval ` sets it explicitly inside the TUI, and `/auto on` toggles auto-approval. Choosing *always allow … in this project* remembers that kind of command for the project, not every command. +Two flags carry the same controls into any invocation, interactive or not. They have short forms, `-a` and `-s`: -## Sandbox +```bash +cortex --ask-for-approval on-request +cortex --sandbox workspace-write +``` -The sandbox limits what a tool may touch when it does run. +| `--ask-for-approval` | When you are asked | +| --- | --- | +| `untrusted` | Ask for anything not already trusted | +| `on-failure` | Let it run, ask when something fails | +| `on-request` | The agent asks when it judges it should. **The default** | +| `never` | Never ask | -| `--sandbox` | What it permits | +| `--sandbox` | What a tool may touch | | --- | --- | | `read-only` | No writes at all | -| `workspace-write` | Writes confined to the workspace (the default) | +| `workspace-write` | Writes confined to the workspace. **The default** | | `danger-full-access` | Everything | -`--full-auto` means automatic execution *inside* the sandbox. `--dangerously-bypass-approvals-and-sandbox` (alias `yolo`) turns both controls off — use it only in a disposable environment. `/sandbox on|off` toggles sandboxing from the TUI, and `sandbox_workspace_write` in `config.toml` refines the workspace policy (extra writable roots, network access). +`--full-auto` means run without asking, but still inside the sandbox. `--add-dir` adds another directory that should be writable for one run. `trusted_directories` in `config.toml` looks like the persistent version of the same idea, but nothing in this build reads it. -When the sandbox blocks something, the timeline says so and offers a way through — keep it blocked, allow once, or allow for this session: + +`--dangerously-bypass-approvals-and-sandbox`, aliased `yolo`, turns off both gates at once: nothing asks and nothing is confined. Use it only in a throwaway environment you are willing to lose. + - - Cortex CLI sandbox denial with three numbered options - +## One idea, four vocabularies + +The same underlying control is named differently depending on where you meet it. This table is the map, not an equivalence: + +| Where you are | What it is called | +| --- | --- | +| The composer | Mode chips, the approval prompt, the three session presets | +| `config.toml` | `approval_policy` and `sandbox_mode` | +| Slash commands | `/approval`, `/sandbox`, `/auto` | +| Headless runs | `--auto`, with levels `read-only` (the default), `low`, `medium` and `high`. `cortex exec` runs `read-only` and `high` only | + + +`--auto read-only` asks unless the action is trusted, and holds the sandbox read-only. `--auto high` never asks, and allows workspace writes with network access. `low` and `medium` sit between them in the flag's value set, but `cortex exec` refuses both before submitting a turn, so there is no third and fourth behaviour to plan around. [Headless and one-shot runs](/cli/headless) has the refusal message. + ## The permission table -`config.toml` can set per-capability policy — `allow`, `ask`, or `deny` — including patterns for shell commands, individual skills, and MCP servers: +`config.toml` can set policy per capability, and each value is `allow`, `ask` or `deny`. This is the control to reach for when you want one command family refused everywhere, regardless of mode: ```toml [permission] edit = "ask" webfetch = "allow" +doom_loop = "ask" external_directory = "deny" [permission.bash] @@ -97,15 +126,13 @@ external_directory = "deny" "my-server" = "allow" ``` -`cortex debug config --diff` shows what differs from the defaults. See [Configuration](/cli/configuration). +A `deny` here wins over the mode and over any approval you give at the prompt. `[permission.bash]` matches shell commands by glob, `[permission.skill]` names a [skill](/cli/skills), and `[permission.mcp]` names a [connected server](/cli/mcp). -## Model and effort +`[sandbox_workspace_write]` refines what `workspace-write` allows, with four keys: `writable_roots` for extra directories, `network_access` for outbound network, and `exclude_tmpdir_env_var` and `exclude_slash_tmp` to keep temporary directories out of the writable set. See [Configuration](/cli/configuration), and [Permission policy](/cli/policy) for the rules an organization can set centrally. -`/model` (or **Ctrl+M**) lists the models under their product names — **Cortex Mini 1**, **Cortex 1**, **Cortex Max 1** — and lets you set reasoning effort with **Tab**: **Low** for quick edits and questions, **Medium** for everyday coding (the default), **High** for hard, multi-file changes. `/effort` opens the same radios directly. +## Model and effort - - Cortex CLI /model effort picker with Medium Effort selected - +`/models` lists the models under their product names and `Tab` moves from that list to the reasoning-effort options for the selected model. | Model | Role | | --- | --- | @@ -113,24 +140,29 @@ external_directory = "deny" | **Cortex 1** | Deeper reasoning for hard changes | | **Cortex Max 1** | Longest context; bills by token instead of per request | -Web Chat's picker shows the same family as Cortex 1 Mini and Cortex Teutonic-1 — see [Models](/chat/models). +The three effort options carry their own one-line descriptions on screen: -## Autonomy in headless runs +- **Low Effort**: `Fastest responses for quick edits and questions` +- **Medium Effort**: `Balanced reasoning for everyday coding · default` +- **High Effort**: `Deepest reasoning — best for hard, multi-file changes` -There is nobody to ask in `cortex exec`, so `--auto` is the control that matters: `read-only` (default), `low`, `medium`, `high`. See [Headless runs](/cli/headless). +`Enter` applies an effort and `Tab` goes back to the model list. The current effort is part of the model chip on the composer, drawn as `Cortex Mini 1 (medium)`. ## Which control do I want? -| I want to… | Use | +| I want to | Use | | --- | --- | -| Explore without any change | Mode **Ask**, or `--sandbox read-only` | +| Explore without changing anything | Mode **Ask**, or `--sandbox read-only` | | See the approach first | Mode **Plan**, or `/spec` for a structured plan with a hard lock | -| Let it work but confirm installs and deletes | Mode **Agent** with **Smart** permissions | +| Let it work but confirm installs and deletes | Mode **Agent** with the **Smart** preset | | Never be interrupted, but stay inside the project | `--full-auto` | -| Forbid one command family everywhere | `[permission.bash] "rm *" = "deny"` | +| Forbid one command family everywhere | `[permission.bash]` with `"rm *" = "deny"` | +| Run a task with nobody there to ask | `cortex exec --auto read-only`, raising the level only as far as you need | ## Related -- [The TUI](/cli/tui) — where the indicators live. -- [Configuration](/cli/configuration) — `approval_policy`, `sandbox_mode`, `permission`. -- [Bot approvals](/bot/approvals) — the same idea in Bot. +- [The TUI](/cli/tui) - where the chips, the prompt and the footer hints live +- [Plan and Spec modes](/cli/plan-mode) - the read-first modes in detail +- [Configuration](/cli/configuration) - `approval_policy`, `sandbox_mode` and the permission table +- [Permission policy](/cli/policy) - organization-wide rules +- [Headless and one-shot runs](/cli/headless) - autonomy when there is no prompt to answer diff --git a/cli/plan-mode.mdx b/cli/plan-mode.mdx new file mode 100644 index 0000000..9a39de2 --- /dev/null +++ b/cli/plan-mode.mdx @@ -0,0 +1,93 @@ +--- +title: "Plan and Spec modes" +description: "Have Cortex work out what it would do before anything changes: Plan mode, Spec mode, and what a structured plan contains" +icon: "list-check" +--- + +Sometimes you want the agent to work out *what* it would do before it does anything at all. The CLI has two read-first modes for that. **Plan** mode is read-only: the agent searches, reads and reasons, and proposes an approach. **Spec** mode goes further: the agent submits a structured plan and the tools that would change your project stay locked until that plan is accepted. + +This page covers how to enter each mode, how the read-only lock is enforced, what you do with a plan once it is on screen, what a structured plan contains, and the two related surfaces you will meet while planning: the question form the agent can put on screen, and delegated investigation. + +## Plan mode + +Cycle with `Shift+Tab` until the mode chip on the composer reads `Plan · no edits`. The placeholder changes to `Describe what you want — Cortex drafts a plan first`, which is the invitation to describe an outcome rather than a change. + +In this mode the agent can read files, search the project and reason about it. It cannot write a file and it cannot run a command that changes anything. Use it when you are new to an area of the codebase, when you want an estimate of a change before committing to it, or when you simply do not want anything touched yet. + +Plan mode is also a built-in agent, so you can get one planning answer without entering the mode: + +```bash +cortex run --agent plan "how should we restructure the storage layer?" +``` + +## The lock is real + +Plan mode is not a polite instruction to the model. The mutating tools are withheld by the agent harness, so they are not available to be called. It is a hard stop rather than a promise: it does not depend on the model choosing to behave. The same is true of Ask mode, and Spec mode extends the idea to a plan you have to accept. + +That is worth knowing because it changes how you read the transcript. If the agent says it will leave a file alone in Agent mode, that is a statement of intent. In Plan mode it is a statement of fact. + +## Accept a plan, or keep going + +When a plan is ready the TUI asks what to do with it, with two options: + +- `Yes, switch to Agent mode and implement` +- `No, keep planning` + +Accepting switches the session to Agent mode and starts the work, which means the usual approval prompts and sandbox apply from that point on. Declining keeps you in Plan mode with the plan on screen, so you can correct an assumption and have it redrafted. Nothing has changed on disk either way. See [Modes and permissions](/cli/modes-and-permissions) for what happens after the switch. + +## Spec mode + +Spec mode is a toggle rather than a step in the mode cycle: + +```text +/spec # enter specification mode +/spec off # leave it +``` + +In Spec mode the agent calls its planning tool and submits a structured plan for review instead of a wall of prose. The mutating tools stay locked until that plan is accepted; the agent then leaves the mode explicitly, giving a reason as it does, and only at that point can it start editing files and running commands. + +Headless runs can start in it too, which is the way to get a plan out of a script: + +```bash +cortex exec --use-spec "add rate limiting to the public API" +cortex exec --use-spec --spec-model "add rate limiting to the public API" +``` + +`--spec-model` lets the planning pass use a different model from the one that would carry out the work. See [Headless and one-shot runs](/cli/headless). + +## What a structured plan contains + +A submitted plan always carries: + +| Part | What it is | +| --- | --- | +| Title | A short name for the work | +| Description | What the change is and why | +| Tasks | The steps it intends to carry out, each with a complexity rating | +| Agent analyses | The reading of the problem from each agent involved | + +It can also carry the architecture it assumes, the technology it intends to use, the use cases it is designing for, the risks it can see, the criteria it would call success, a timeline, and an estimate of the changes involved. Those extras appear when they apply, so a small plan is short. + +## Why plan first + + +Three reasons the read-first modes earn their keep: you see the shape of the work while it is still cheap to redirect; the plan is a structured artefact rather than a paragraph, so it survives being pasted into an issue or a design review; and the block on mutating tools is enforced rather than promised. + + +## When the agent asks you a question + +Independently of either mode, the agent can put a short structured form on screen when it needs a decision from you rather than a guess. A question is single choice, multiple choice, free text or a number, and the composer placeholder changes to `Choose an option above` while one is open. Answering the form is usually faster and less ambiguous than a round trip through prose. + +## Delegated investigation + +Planning often means reading more of the project than one turn can hold, so the agent can delegate. A delegated task runs in one of three roles: `explore` for read-only investigation, `plan` for producing a plan, and `worker` for carrying out a slice of the work. + +Two limits are worth knowing. A delegated task cannot delegate further, and it cannot talk to you directly: it reports back through the turn that spawned it, which is why you see its result as a single tile in the timeline. `/tasks` lists what is running in the background. See [Agents and subagents](/cli/agents) and [Tools the agent uses](/cli/tools). + +## Related + +- [Modes and permissions](/cli/modes-and-permissions) - the mode cycle, approvals and the sandbox +- [The TUI](/cli/tui) - the mode chip, the placeholder and the timeline +- [Agents and subagents](/cli/agents) - the built-in planning and exploring agents +- [Headless and one-shot runs](/cli/headless) - `--agent plan`, `--use-spec` and `--spec-model` +- [Tools the agent uses](/cli/tools) - which tools a mode withholds diff --git a/cli/plugins.mdx b/cli/plugins.mdx new file mode 100644 index 0000000..2d9b728 --- /dev/null +++ b/cli/plugins.mdx @@ -0,0 +1,254 @@ +--- +title: "CLI plugins" +sidebarTitle: "Plugins" +description: "Install, review, trust and build Cortex CLI plugins: the plugin commands, the manifest, manifest hooks, and the limits a plugin cannot cross." +icon: "puzzle-piece" +--- + +A plugin is a package that adds something to the Cortex CLI: extra slash commands, extra tools the agent can call, configuration of its own, and hooks that observe or block what a session does. Plugins are compiled to WebAssembly and run in a sandbox with a memory cap, an instruction budget and a wall-clock timeout, so a plugin that misbehaves is stopped instead of taking your session with it. + +This page covers the plugin lifecycle end to end: where plugins live, how to review a package before you install it, how to enable, run, update and remove one, what the manifest declares, and the security model that decides what a plugin is allowed to do. The catalogue of hook events lives on [Hooks](/cli/hooks). + + +The plugin surface is young. Installation, enablement, the local development workflow and the manifest format are real and stable enough to build against. The `search`, `browse` and `update` subcommands talk to a plugin registry that is not documented publicly yet, and `publish` runs as a dry run by default, preparing the package locally and reporting what it would ship. + + +## Where plugins live + +Plugins are read from two roots: + +| Root | Scope | +| --- | --- | +| `~/.cortex/plugins/` | Your own plugins, available in every project | +| `.cortex/plugins/` | Plugins committed with a repository, available to anyone who checks it out | + +A project plugin wins over a personal plugin with the same id. See [Data locations](/cli/data-locations) for the rest of the layout, including where the audit journal is written. + +## The plugin commands + +`cortex plugin` (alias `cortex plugins`) groups everything. Every subcommand accepts `--help`. + +| Command | What it does | +| --- | --- | +| `list` (alias `ls`) | List installed plugins. `--json`, `--enabled`, `--disabled` | +| `install ` (alias `add`) | Install a plugin. `--version`, `-f/--force`, `--json`, `--accept-command `, `--trust-code` | +| `show ` (alias `info`) | Show plugin information. `--json` | +| `enable ` | Enable an installed plugin | +| `disable ` | Disable an installed plugin without removing it | +| `remove ` (aliases `rm`, `uninstall`) | Remove a plugin. `-y` | +| `update ` | Update an installed plugin from the registry. `--source`, `--accept-command `, `--json` | +| `trust ` | Explicitly trust native execution for this installed artifact. `--yes` | +| `run ` | Invoke an installed plugin command or tool through the executable runtime | +| `search ` | Search the plugin registry. `--json` | +| `browse` | Browse plugins in the registry. `--json` | +| `new ` (alias `create`) | Create a new plugin project. `-d`, `-a/--author`, `-o/--output`, `--advanced` | +| `dev` | Rebuild in development mode (no runtime hot-reload). `-p/--path`, `-w/--watch`, `--debounce-ms` | +| `build` | Build the plugin artifact. `-p/--path`, `--debug`, `-o/--output` | +| `validate` (alias `check`) | Validate plugin manifest and structure. `-p/--path`, `--json`, `-v` | +| `publish` | Prepare plugin for publication (dry-run). `-p/--path`, `-o` | + +Inside a session, `/plugins` opens the same list without leaving the timeline: `Enter` toggles the selected plugin, `i` installs, `u` updates and `Esc` closes. + +## Install a plugin, after reading what it registers + +Installing a plugin is a two-step review. The first step prints what the package would add and a hash of that surface. The second step installs only if the hash still matches. + + + +```bash +cortex plugin install my-plugin --json +``` + +`--json` prints the review and the hash without installing anything: the plugin id and version, every command with its aliases and arguments, every hook and tool it registers, and a `command_hash` over that surface. + + +Treat the command list as the security boundary. A plugin that registers a hook on tool execution sees every tool call in the session, and a plugin that registers a tool adds something the agent can decide to call on its own. If a name or a scope surprises you, stop here. + + +```bash +cortex plugin install my-plugin --accept-command 8f4c9d21b7e0a5c3e2d1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9 +``` + +`--accept-command` takes the exact sha256 the review printed, all 64 characters of it: a shorter value is refused with `Accept-command hash must be a 64-character SHA-256 value from --json.` If the package changed in between, the install fails with `Command hash mismatch. Manifest may have changed. Re-run with --json and accept the new hash.` + + + +The failure is a clean one: nothing is written to the plugin root, an already-installed copy is left exactly as it was, and no trust decision is renewed. There is no flag that accepts whatever hash happens to be current, so a changed manifest always comes back to you. Accepted hashes are appended to the audit journal with the plugin, the hashes and the scope names, never prompt text or file contents. + + +Run the review step in CI too. A pinned hash in a repository script means a plugin that quietly grows a new command fails the build instead of shipping. + + +Organisations can require the pinned form and refuse unreviewed installs. See [Permission policy](/cli/policy). + +## Packages that execute native code + +Most plugins run in the WebAssembly sandbox and need no extra decision. A package that executes native code cannot be sandboxed, so it is refused until you say otherwise, once, in writing: + +```bash +cortex plugin install my-plugin --accept-command 8f4c9d21b7e0a5c3e2d1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9 --trust-code +cortex plugin trust my-plugin --yes +``` + + +`--trust-code` trusts that exact package to execute native code. It is not a sandbox. A trusted package can read and write files, reach the network and start subprocesses with your user's rights, and `cortex plugin trust --yes` is you acknowledging exactly that. There is no signing or content verification of plugin packages today, so trust the source or do not trust the package. + + +## Enable, disable, remove + +```bash +cortex plugin list --enabled +cortex plugin disable my-plugin +cortex plugin enable my-plugin +cortex plugin remove my-plugin -y +``` + +Disabling is the safe way to isolate a plugin while you debug something: the package stays installed and its hooks stop running. A plugin that is unloaded or disabled is skipped silently when hooks dispatch. A plugin in any other non-active state is an error rather than a silent skip, and the session reports `Plugin is not active`. + +## Run a command or a tool directly + +`cortex plugin run` invokes a plugin outside a session, which is how you test one: + +```bash +cortex plugin run my-plugin review --json +cortex plugin run my-plugin --tool summarise --input '{"path":"README.md"}' +``` + +A command name and `--tool` are mutually exclusive, and one of the two is required. `--input` takes a JSON object, requires `--tool`, and defaults to `{}`. `--json` prints a machine-readable report of the invocation. + +## What the manifest declares + +Every plugin has a `plugin.toml` at its root. It declares the capabilities the plugin uses, the permissions it asks for, and the commands, hooks, tools and configuration it registers. + +```toml +capabilities = ["commands", "hooks", "config"] +permissions = [ + { read_file = { paths = ["src/**/*"] } }, + { network = { domains = ["example.com"] } }, +] + +[plugin] +id = "my-plugin" +name = "My Plugin" +version = "1.0.0" +description = "What it does" +authors = ["Your Name"] +license = "Apache-2.0" +min_cortex_version = "0.1.0" + +[[commands]] +name = "review" +aliases = ["rv"] +description = "Review the current diff" +usage = "/review [target]" +category = "quality" + +[[commands.args]] +name = "target" +description = "What to review" +required = false +default = "HEAD" +arg_type = "string" + +[[hooks]] +hook_type = "tool_execute_before" +priority = 100 +pattern = "Edit" +function = "hook_tool_execute_before" + +[config] +strict = { description = "Fail on any finding", type = "boolean", default = false, required = false } + +[wasm] +memory_pages = 128 +timeout_ms = 5000 +wasi_enabled = true +wasi_caps = ["stdout", "stderr", "clocks"] +``` + +`capabilities` names the broad areas a plugin touches. There are ten: `commands`, `hooks`, `events`, `tools`, `formatters`, `themes`, `config`, `filesystem`, `shell` and `network`. `permissions` is the scoped list: `read_file`, `write_file`, `execute`, `network`, `environment` and `config` each take the paths, commands, domains, variables or keys they apply to, while `clipboard` and `notifications` take no scope and are written as bare strings in the same array. A plugin that asks for `read_file` with `paths = ["**/*"]` is asking for your whole workspace; narrow scopes are easier to accept. + +`[[tools]]` blocks add tools the agent can call, each with a JSON input schema. `[config]` keys become settings a user can set, with an optional `[config..validation]` table. `[wasm]` tunes the sandbox inside the hard ceilings below, and a package that uses the executable runtime declares it in `[runtime]`. + +## Hooks in the manifest + +Hooks reach a session through the manifest, not through a separate file. Each `[[hooks]]` block has exactly four fields, and an unknown field is a manifest error rather than a warning: + +| Field | Required | Meaning | +| --- | --- | --- | +| `hook_type` | Yes | Which event the hook subscribes to, in snake case, for example `session_start` or `tool_execute_before` | +| `priority` | No, default `100` | Lower runs first | +| `pattern` | No | Narrows the hook, for example to one tool name | +| `function` | No | The function in the package to call | + +When several plugins subscribe to the same event, they run in a deterministic order: lowest priority number first, and plugins that share a priority keep the order they were registered in, so the same set of plugins always produces the same sequence. [Hooks](/cli/hooks) lists the events you can subscribe to and what each one receives. + +## What a hook can and cannot do + +A hook can watch, annotate, and refuse. It cannot widen what a session is allowed to do, and that is enforced in two places rather than one. + +Every permission question starts at **ask**. A hook that answers "allow" does not get its way: the dispatch fails with `Plugins cannot grant execution privileges`, and a third-party plugin attempting it is refused with `Third-party plugins cannot auto-grant permissions (security restriction)`. The engine re-checks the same rule after the hooks have run, so a plugin cannot slip an approval through by answering late. A hook can deny an action, and the first non-ask decision wins, so one plugin's refusal is enough to stop a call. + +Two further edits are rejected outright. A hook cannot change which tool is about to run or drop its arguments (`A hook cannot change tool identity or remove arguments`), and a hook cannot promote the role of a message it touches (`Hooks cannot elevate message roles`). The practical summary: a plugin can make your session stricter, never looser. Approvals stay with you and with your [permission policy](/cli/modes-and-permissions). + +## The sandbox ceilings + +These limits are the outer bounds, whatever a manifest asks for: + +| Limit | Value | +| --- | --- | +| Memory | 16 MB, 256 pages of 64 KB | +| Instruction budget | 10,000,000 fuel operations | +| Execution timeout | 30 seconds by default | +| Table elements | 10,000 | +| Instances per plugin | 10 | +| Memory regions | 1 | +| Tables | 10 | + +A plugin that loops forever runs out of fuel or hits the timeout and is terminated. Your session keeps going. + +## Build your own + + + +```bash +cortex plugin new my-plugin -a "Your Name" +``` + +Add `--advanced` for a template that includes interface hooks. + + +```bash +cortex plugin validate -p ./my-plugin --json +``` + +Validation checks the manifest and the project structure, and is the fastest way to catch a mistyped `hook_type` or an unknown field. + + +```bash +cortex plugin build -p ./my-plugin +cortex plugin dev -p ./my-plugin --watch --debounce-ms 500 +``` + +`dev --watch` rebuilds on change, with a debounce so a burst of saves is one rebuild. It rebuilds the artifact; it does not hot-reload a running session, so reload the plugin to pick up a new build. + + +```bash +cortex plugin install ./my-plugin --json +cortex plugin install ./my-plugin --accept-command +``` + +The review and hash step is the same for a local path as for a registry package. + + + +`cortex plugin publish` prepares the package and reports what it would ship. Dry-run is the default, as its own help says: `Dry-run mode (default, no actual publishing)`. + +## Related + +- [Hooks](/cli/hooks) +- [Tools the agent uses](/cli/tools) +- [Modes and permissions](/cli/modes-and-permissions) +- [Permission policy](/cli/policy) +- [Command reference](/cli/reference) +- [Data locations](/cli/data-locations) diff --git a/cli/policy.mdx b/cli/policy.mdx new file mode 100644 index 0000000..0119a80 --- /dev/null +++ b/cli/policy.mdx @@ -0,0 +1,139 @@ +--- +title: "Permission policy" +description: "Set allow, ask and deny rules for tools and commands in Cortex CLI, restrict the sandbox, and understand a managed organization policy." +icon: "file-shield" +--- + +Permission policy is how you decide, in advance, what the agent may do without stopping to ask you. It has two layers that are easy to confuse. The first is yours: keys in a config file that set the approval policy, the sandbox and per-tool rules, which you can also commit to a repository. The second only exists if your organization pins settings on the machine, and it can restrict two specific behaviours no matter what your own config says. + +This page covers the rules you write yourself first, then the managed document separately. If you are looking for the interactive controls instead, the mode chip, the approval prompt and the presets are on [Modes and permissions](/cli/modes-and-permissions). + +## Your own rules + +Three keys do most of the work. They go in `~/.cortex/config.toml`, or in a project `.cortex/config.toml`. + +| Key | Values | Meaning | +| --- | --- | --- | +| `approval_policy` | `untrusted`, `on-failure`, `on-request`, `never` | When to ask before running a tool. `on-request` is the default. | +| `sandbox_mode` | `read-only`, `workspace-write`, `danger-full-access` | What the sandbox permits. `workspace-write` is the default. | +| `trusted_directories` | array of paths | Read from both layers and merged, but nothing in this build consults the merged list. Do not rely on it to skip a prompt. | + +`[sandbox_workspace_write]` refines the default sandbox mode: + +```toml +sandbox_mode = "workspace-write" + +[sandbox_workspace_write] +writable_roots = ["/tmp/scratch"] +network_access = false +exclude_tmpdir_env_var = false +exclude_slash_tmp = false +``` + +## The permission table + +`[permission]` sets policy per capability and per command. Every value is `allow`, `ask` or `deny`. + +```toml +[permission] +edit = "ask" +webfetch = "allow" +doom_loop = "ask" +external_directory = "deny" + +[permission.bash] +"git *" = "allow" +"rm *" = "deny" + +[permission.skill] +"deploy" = "ask" + +[permission.mcp] +"my-server" = "allow" +``` + +The sub-tables match on the thing being run: a glob over shell commands under `[permission.bash]`, a skill name under `[permission.skill]`, a server name under `[permission.mcp]`. This is the surface to reach for when you want one dangerous command family blocked outright rather than approved case by case. + +The same controls exist as flags for a single run, `-a` / `--ask-for-approval`, `-s` / `--sandbox`, `--full-auto` and `--dangerously-bypass-approvals-and-sandbox`, and as the slash commands `/approval `, `/sandbox [on|off|network]` and `/auto [on|off]` inside a session. + +## Project rules + +A project `.cortex/config.toml` can carry `approval_policy`, `sandbox_mode` and the whole `[permission]` table, and it beats your own config. A repository can also commit `.cortex/permissions.toml`, a rules file the session loads and evaluates rather than merely displays: `First matching rule wins; deny beats allow.` `/permissions rules` shows how many allow, ask and deny rules are in effect, and answers `No permission rules committed. Add .cortex/permissions.toml to pin allow / ask / deny.` when there are none. And a repository can commit `.cortex/sandbox.toml`, which restricts network egress for runs in that repository, so every run and every CI job inherits the same restriction. + + +Because the project layer wins, cloning a repository can loosen or tighten what the agent may do on your machine. Run `cortex config` in a fresh clone before you start a session in it. See [Configuration](/cli/configuration). + + +## A hook is never consent + +What a hook cannot do is stand in for your approval. A hook firing is not consent, and it does not remove the approval prompt that the policy above would otherwise raise. A hook cannot grant a permission either: every permission question starts at "ask", a hook may answer "deny", and a plugin that tries to answer "allow" is refused outright. + +Hooks are declared by a plugin, in that plugin's manifest, rather than in a file of their own, and they do not fire around the tool calls an interactive session makes. The policy above is what gates a session. [Hooks](/cli/hooks) covers the events and which of them actually fire. + +## If your organization pins settings + +A managed policy is a separate mechanism from everything above. It is one directory, named by `CORTEX_ORG_POLICY_DIR`, holding one file, `policy.json`: + +```bash +export CORTEX_ORG_POLICY_DIR=/etc/cortex/policy +``` + +There are exactly two keys, both optional: `fast_mode` and `plugin_install`. A missing document, or a document without a key, leaves that key on the host default. Two keys is the whole surface today. + +Every key resolves fail-closed. A document that exists but cannot be read, cannot be parsed, or carries a value that is not recognized denies the restricted behavior. Policy failures never grant a permission. + +| Situation | `fast_mode` | `plugin_install` | +| --- | --- | --- | +| No directory, or no `policy.json` | host default | host default | +| Key absent | host default | host default | +| Key `true`, `"on"`, `"enabled"`, `"allowed"` | allowed | optional | +| Key `false`, `"off"`, any other value | disabled | required | +| Document unreadable or unparseable | disabled | required | + +### When fast mode is disabled + +A request to turn fast mode on is refused with this message, then a second line saying the session is staying where it is: + +```text +Fast mode is disabled for your organization. Contact your admin. +Staying on Standard. +``` + +The session keeps its current model and settings. Nothing is re-sent, and there is no client flag that bypasses the policy. Turning fast mode off is always allowed, so the policy only ever restricts in one direction. A remote session on Standard shows `Remote · Standard`; the Fast chip appears only while fast mode is actually on. + +### When plugin installs require a review + +With `plugin_install` set to require an accepted command, installing or updating a plugin refuses until you have reviewed what it would run and passed the hash back: + +```text +This organization requires --accept-command for plugin installs. +Run `cortex plugin install --json` to review the commands, +then pass --accept-command . +``` + +The pin itself is enforced the same way for every organization, so a review that does not match the package fails closed whether or not a policy document exists. See [CLI plugins](/cli/plugins). + +### The audit journal + +Fail-closed decisions append one JSON object per line to `audit/events.jsonl` in the Cortex home directory. + +| Kind | Written when | +| --- | --- | +| `plugin_command_accepted` | A reviewed command hash was accepted for an install or update | +| `instructions_omitted` | A subagent skipped user, project, or local instruction documents | +| `managed_policy_never_omitted` | A request named managed policy; it loaded anyway | + +Records carry the plugin or source, the hashes, and the scope names. They never carry prompt text, file bodies, or secrets. + + +How an organization puts `policy.json` on a machine is up to that organization, and there is no administration screen for it in the CLI. If you hit one of the refusals above and you do not manage the machine, the message is right: ask whoever does. + + +## Related + +- [Modes and permissions](/cli/modes-and-permissions) +- [Configuration](/cli/configuration) +- [Environment variables](/cli/environment-variables) +- [Hooks](/cli/hooks) +- [CLI plugins](/cli/plugins) +- [Data locations](/cli/data-locations) diff --git a/cli/quickstart.mdx b/cli/quickstart.mdx index 4bc42d2..c65da92 100644 --- a/cli/quickstart.mdx +++ b/cli/quickstart.mdx @@ -1,103 +1,144 @@ --- title: "CLI quickstart" -description: "From nothing installed to a working Cortex Code session in the terminal — install, sign in, first turn, AGENTS.md, and how much autonomy to grant." -image: "/images/banners/code.png" -keywords: ["tutorial", "first run", "getting started"] +description: "From nothing installed to a finished first turn in a project: install, sign in, start a session, write AGENTS.md, and choose an autonomy level" +icon: "rocket" --- -Ten minutes, end to end. The TUI and `cortex exec` run on the **Cloud** Code runtime by default, so a fresh install completes a turn without any extra configuration. +This is the ten-minute path from nothing installed to a first piece of work finished in one of your own repositories. You need a terminal, a Cortex account, and a project to point it at. - - Cortex CLI first-run tips panel above the empty composer - +Sessions run on the Cloud host by default, so a fresh install completes a turn with no extra configuration. Nothing here assumes you have used Cortex before, and each step links to the page that covers it properly. - - - ```bash macOS and Linux - curl -fsSL https://software.cortex.foundation/install.sh | sh - ``` + + + + ```bash + curl -fsSL https://software.cortex.foundation/install.sh | sh + ``` + + + ```powershell + irm https://software.cortex.foundation/install.ps1 | iex + ``` + + + + Then check it: - ```powershell Windows - irm https://software.cortex.foundation/install.ps1 | iex + ```bash + cortex --version ``` - - Then `cortex --version`. Details and options: [Install](/cli/install). + If the command is not found, the install directory is not on your `PATH`. [Install the CLI](/cli/install) has the exact locations and the options for pinning a version. + ```bash cortex login ``` - The browser opens; approve the sign-in. `cortex whoami` confirms it. No browser on this machine? `cortex login --device-auth`. See [Sign in](/cli/sign-in). + A sign-in page opens in your browser; approve it there and the CLI continues. `cortex whoami` confirms the account. On a machine with no browser, use `cortex login --device-auth` and enter the printed code on another device. See [Sign in](/cli/sign-in). + ```bash cd ~/code/my-project cortex ``` - The session view opens: a timeline, a composer at the bottom, and a footer with the model and mode — `Cortex Mini 1 · Agent`. Type what you want changed and press **Enter**. + The session view opens: a timeline above, a composer at the bottom with the placeholder `Plan, search, build anything`, the mode chip reading `Agent` at its top left, and the model chip, for example `Cortex Mini 1 (medium)`, at its bottom right. + + On a first run you also get the tips panel: + + ```text + A few tips to get the most out of this tool: + 1. Use /model to switch between models and adjust reasoning effort. + 2. Add @ files to give Cortex the right context. + 3. Press Shift+Tab anytime to cycle Agent / Plan / Ask. + 4. Ctrl+x lists every shortcut · F2 opens settings. + ``` + + Typing `/` opens the command list, and `/models` is the entry for picking a model and its reasoning effort. + + Now type what you want and press **Enter**: ```text - > add a /healthz endpoint and cover it with a test + add a /healthz endpoint and cover it with a test ``` - Cortex works through the request as a series of tool calls — searching, reading, editing, running commands — and each appears on the timeline as it happens. Press **Esc** to interrupt a turn that is going the wrong way. + Cortex works through the request as a series of tool calls, searching, reading, editing and running commands, and each one appears in the timeline as a row while it happens. The turn ends with a line like `Worked for 12s`. - - Cortex CLI thinking on a prompt, with Add a follow-up — Enter to queue in the composer - + Press **Esc** to interrupt a turn that is heading the wrong way; the timeline marks it `Stopped`. While a turn is running the composer still accepts text, but **Enter** queues a follow-up instead of sending it. - + + ```bash cortex init ``` - Writes an `AGENTS.md` in the current directory. Cortex reads it at the start of every session, so put build commands, test commands, house style, and anything a new contributor would need there. `/init` does the same from inside the TUI. + This writes an `AGENTS.md` in the current directory, and `/init` does the same from inside a session. Cortex reads that file at the start of every session in the project, so put the build command, the test command, house style, and anything a new contributor would need to be told into it. Add `--force` to overwrite an existing file. + + A good `AGENTS.md` is the single highest-value thing you can do for the quality of later turns. + - Every session runs under an approval policy and a sandbox. By default Cortex asks before it does anything consequential. Press **Shift+Tab** to cycle **Agent → Plan → Ask**, use `/permissions` to pick **Read-only**, **Smart**, or **Full access**, or set it up front: + Every session runs under an approval policy and a sandbox. The defaults are `approval_policy = "on-request"`, so the agent asks before anything consequential, and `sandbox_mode = "workspace-write"`, so writes stay inside the workspace. + + Press **Shift+Tab** to cycle the mode. The chip at the top left of the composer tells you where you are: + + | Mode | Chip | What it allows | + | --- | --- | --- | + | Agent | `Agent` | Read, write and run, with approvals | + | Plan | `Plan · no edits` | Read and reason, no changes | + | Ask | `Ask · read-only` | Questions about the codebase only | + + Plan and Ask are enforced by the harness, not by asking the model to behave: the mutating tools are withheld outright. + + Or set the policy when you start the session: ```bash - cortex --ask-for-approval on-request # ask when the agent requests it (default) + cortex --ask-for-approval on-request # ask when the agent requests it (the default) cortex --sandbox read-only # no writes at all cortex --sandbox workspace-write # writes confined to the workspace - cortex --full-auto # automatic, inside the sandbox ``` - See [Modes and permissions](/cli/modes-and-permissions). + When the agent wants to run a command you get a numbered prompt headed `Cortex wants to run`. Option 1 runs it once, option 2 allows that kind of command in this project from now on, option 3 lets you edit the command first, and option 4 refuses and lets you say what to do instead. See [Modes and permissions](/cli/modes-and-permissions). ## Other ways to start ```bash -cortex "explain this repository" # seed the session with a prompt -cortex --cd /path/to/project # another working root -cortex --profile work # a profile from config.toml -cortex resume --last # pick up where you left off -cortex run "explain the release process" # one-shot, streamed, no TUI -cortex exec --auto read-only --git-diff "review my uncommitted changes" # headless +cortex "explain this repository" # open a session seeded with a prompt +cortex --cd /path/to/project # work in another directory +cortex --profile work # use a profile from config.toml +cortex resume --last # pick up the most recent session +cortex run "explain the release process" # one-shot, streamed, no session view +cortex exec --auto read-only --git-diff "review my uncommitted changes" ``` -The TUI needs a terminal on both stdin and stdout. In a pipeline or a CI job, use [`cortex run` or `cortex exec`](/cli/headless). +The session view needs a real terminal on both standard input and standard output. In a pipeline or a scheduled job, use `cortex run` or `cortex exec` instead: see [Headless and one-shot runs](/cli/headless). + + +Every turn goes to the Cortex coding service; the CLI does not run a model on your machine. If the service cannot be reached you get `The coding service is temporarily unavailable` and a non-zero exit status, never a quiet fallback. + ## Where to go next -| Want to… | Read | +| Want to | Read | | --- | --- | | Understand everything on screen | [The TUI](/cli/tui) | +| Get a plan before anything changes | [Plan and Spec modes](/cli/plan-mode) | | Learn the `/` commands | [Slash commands](/cli/slash-commands) | | Keep the agent working toward a bigger objective | [Goals](/cli/goal) | -| Resume, export, or share a session | [Sessions](/cli/sessions) | -| Run in CI | [Headless runs](/cli/headless) | -| Connect an MCP server or write a skill | [Extend](/cli/extend) | +| Resume, export or share a session | [Sessions](/cli/sessions) | +| Run it in a pipeline | [CI cookbook](/cli/ci) | +| Connect an MCP server or write a skill | [MCP servers](/cli/mcp) and [Skills](/cli/skills) | ## Related -- [Install](/cli/install) — checksums, version pins, and channels. -- [Sign in](/cli/sign-in) — the browser flow, device codes, and CI keys. -- [Modes and permissions](/cli/modes-and-permissions) — decide how much the agent may do. -- [CLI troubleshooting](/cli/troubleshooting) — the terminal. +- [Install the CLI](/cli/install) +- [Sign in](/cli/sign-in) +- [Modes and permissions](/cli/modes-and-permissions) +- [Cortex CLI](/cli/index) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/reference.mdx b/cli/reference.mdx new file mode 100644 index 0000000..b132b2c --- /dev/null +++ b/cli/reference.mdx @@ -0,0 +1,272 @@ +--- +title: "Command reference" +description: "The supported cortex command surface: global options, run and exec, sessions, auth, bounty, agents, MCP, plugins, config, utilities and maintenance." +icon: "book" +--- + +This is the supported command surface of the Cortex CLI, one table per group. The generated help is always authoritative: `cortex --help` and `cortex --help` come from the same definitions this page describes, so if a flag here disagrees with your installed build, believe the build and check your version with `cortex --version`. + +Two invocation forms exist, and the first one has two meanings: + +```bash +cortex [OPTIONS] [PROMPT] +cortex [OPTIONS] [ARGS] +``` + +With no subcommand and a terminal attached, `cortex` starts the interactive interface, and a positional prompt seeds that first session. Without a terminal, use [`run` or `exec`](/cli/headless). Global options go before the subcommand. + +## Global options + +| Flag | Description | +| --- | --- | +| `-c`, `--config ` | Configuration override, repeatable | +| `-v`, `--verbose` | Verbose output, equivalent to `--log-level debug` | +| `--trace` | Trace-level logging | +| `--color ` | Colour output, default `auto` | +| `-m`, `--model ` | Model to use | +| `--oss` | Use local or open providers instead of the hosted service | +| `-p`, `--profile ` | Profile from `config.toml` | +| `-s`, `--sandbox ` | `read-only`, `workspace-write`, `danger-full-access` | +| `-a`, `--ask-for-approval ` | `untrusted`, `on-failure`, `on-request`, `never` | +| `--full-auto` | Automatic execution inside the sandbox | +| `--dangerously-bypass-approvals-and-sandbox` | No prompts, no sandbox. Aliased `yolo`. | +| `-C`, `--cd ` | Working root for the agent | +| `--add-dir ` | Extra writable directory, repeatable | +| `-i`, `--image ` | Attach an image to the initial prompt | +| `--search` | Enable web search | +| `--alternate-screen` / `--no-alternate-screen` | Take the full viewport, or stay inline in the host terminal. Same as `[tui] alternate_screen`. | +| `--max-agent-threads ` | Concurrent agent threads | +| `--max-tool-threads ` | Concurrent tool executions | +| `--command-timeout ` | Shell command timeout | +| `--http-timeout ` | HTTP request timeout | +| `--no-streaming` | Disable streaming responses | +| `-L`, `--log-level ` | `error`, `warn`, `info`, `debug`, `trace`. Default `info`. | +| `--debug` | Record bounded, content-free local diagnostics under the Cortex home `diagnostics/` directory, or `CORTEX_DIAGNOSTICS_DIR` | +| `-h`, `--help` | Help | +| `-V`, `--version` | Version | + + +`--dangerously-bypass-approvals-and-sandbox` turns off both gates at once: nothing asks, and nothing is confined. Use it only in a throwaway environment you are willing to lose. [Modes and permissions](/cli/modes-and-permissions) explains the safer combinations. + + +## Run the agent + +### cortex run + +Non-interactive and streaming. Alias `r`. Usage: `cortex run [OPTIONS] [MESSAGE]...` + +| Flag | Description | +| --- | --- | +| `--command ` | Run a predefined command instead of a prompt | +| `-c`, `--continue` | Continue the most recent session | +| `-s`, `--session ` | Continue a specific session | +| `--share` | Share the session and print the URL | +| `-m`, `--model ` | Model, in `provider/model` form | +| `--agent ` | Agent to use | +| `--format ` | Output format, `--output` is an alias | +| `-f`, `--file ` | Attach a file, repeatable | +| `--title ` | Session title | +| `--attach <URL>` | Attach to a running server | +| `--port <PORT>` | Local server port | +| `-t`, `--temperature <N>` | 0.0 to 2.0 | +| `--top-p`, `--top-k`, `--seed` | Sampling controls | +| `-n`, `--notification` | Desktop notification when finished | +| `--stream` / `--no-stream` | Stream or buffer the response | +| `-C`, `--copy` | Copy the final response to the clipboard | +| `-o`, `--output-file <PATH>` | Write the final response to a file | +| `--cwd <PATH>` | Working directory | +| `--add-dir <DIR>` | Extra writable directory | +| `--timeout <SECONDS>` | `0` means no timeout | +| `--dry-run` | Preview without executing | +| `--max-tokens <N>` | Response cap | +| `--system <PROMPT>` | Custom system prompt | +| `--schema <PATH>` | JSON schema for structured output | +| `-q`, `--quiet` | Quiet output | +| `--no-progress`, `--no-cache` | Drop progress output, ignore the cache | +| `--retry <N>` | Retry count | +| `--frequency-penalty`, `--presence-penalty`, `--stop`, `--logprobs`, `--n`, `--best-of` | Sampling controls | + +### cortex exec + +Headless execution for CI and scripts. Alias `e`. Usage: `cortex exec [OPTIONS] [PROMPT]...` + +| Flag | Description | +| --- | --- | +| `-f`, `--file <PATH>` | Read the prompt from a file | +| `-o`, `--output-format <FORMAT>` | `text` (default), `json`, `stream-json`, `debug`, `stream-jsonrpc` | +| `--input-format <FORMAT>` | `text` (default) or `stream-jsonrpc` | +| `--auto <LEVEL>` | `read-only` (default), `low`, `medium`, `high` | +| `--skip-permissions-unsafe` | Bypass all permission checks, conflicts with `--auto` | +| `-m`, `--model <MODEL>` | Model | +| `--spec-model <MODEL>` | Model for specification mode | +| `--use-spec` | Start in specification mode | +| `-r`, `--reasoning-effort <LEVEL>` | Reasoning effort | +| `-s`, `--session-id <ID>` | Continue a session | +| `--enabled-tools <LIST>` / `--disabled-tools <LIST>` | Comma-separated allow list and deny list | +| `--list-tools` | Print the available tools and exit | +| `--cwd <PATH>` | Working directory | +| `--max-turns <N>` | Default `100` | +| `--timeout <SECONDS>` | Default `600` | +| `-i`, `--image <PATH>` | Attach an image, repeatable | +| `--system <PROMPT>` | Custom system prompt | +| `--max-tokens <N>` | Response cap | +| `--echo` | Include the prompt in the output | +| `--user <ID>` | User identifier for tracking | +| `--response-format <FORMAT>` | `text`, `json`, `json_object` | +| `--output-schema <SCHEMA>` | Inline JSON or a file path | +| `--url <URL>` | Fetch a URL into the context, repeatable | +| `--clipboard` | Read the clipboard into the context | +| `--git-diff` | Include the git diff | +| `--include <GLOB>` / `--exclude <GLOB>` | Filter files in the context, repeatable | +| `-v`, `--verbose` | Verbose output | +| `--frequency-penalty`, `--presence-penalty`, `--stop`, `--logprobs`, `-n`, `--best-of` | Sampling controls | + +## Sessions + +| Command | Description | +| --- | --- | +| `cortex resume [SESSION_ID]` | Resume a session. `--last`, `--pick`, `--all`, `--no-session`. | +| `cortex sessions` | List sessions. `--all`, `--days`, `--since`, `--until`, `--favorites`, `-s/--search`, `-l/--limit`, `--json`. | +| `cortex export [SESSION_ID]` | Export a session. `-o/--output`, `-f/--format json\|yaml\|csv`, `--pretty`. | +| `cortex import <FILE_OR_URL>` | Import a session. `-f/--force`, `--resume`. `-` reads standard input. | +| `cortex delete <SESSION_ID>` | Delete a session. `-y/--yes`, `-f/--force`. | +| `cortex lock [SESSION_ID]` | Protect sessions from cleanup. Alias `protect`. Subcommands `add`, `remove`, `list`, `check`. | +| `cortex attach [SESSION_ID]` | Attach this terminal to a live Code session. The session keeps running when you detach. | +| `cortex jobs` | List, follow, or stop background Code agents. Subcommands `list`, `logs`, `stop`, `attach`. | + +<Note> +Sharing, forking and rewinding are in-session actions, not subcommands. Use the slash commands `/share`, `/fork` and `/rewind` inside a session, or `cortex run --share` for a one-shot run. See [Sessions](/cli/sessions). +</Note> + +## Authentication + +| Command | Description | +| --- | --- | +| `cortex login` | Sign in. `--with-api-key`, `--token <TOKEN>`, `--device-auth`, `--sso`. Subcommand `status`. | +| `cortex logout` | Sign out. `-y/--yes`, `--all`. | +| `cortex whoami` | Show the signed-in account. | + +## Bounty + +| Command | Description | +| --- | --- | +| `cortex bounty pair --hotkey <ss58>` | Pair a mining hotkey with your Cortex account. `--accept-terms` is required the first time, until the research terms are accepted. See [Pair a hotkey](/bounty/pair-a-hotkey). | + +## Agents + +`cortex agent` manages agents. See [Agents](/cli/agents). + +| Subcommand | Arguments | +| --- | --- | +| `list` | `--json`, `--primary`, `--subagents`, `--all`, `--remote`, `--filter` | +| `show <name>` | `--json`, `--model` | +| `create` | `--name`, `-d/--description`, `--mode`, `--non-interactive`, `--generate <DESCRIPTION>`, `--model` | +| `edit <name>` | `-e/--editor` | +| `remove <name>` | `-f/--force` | +| `install <name>` | `-f/--force`, `--registry` | +| `copy <source> <destination>` | `-f/--force`. Alias `clone`. | +| `export <name>` | `-o/--output`, `--json` | + +## MCP servers + +`cortex mcp` manages connected servers. See [MCP servers](/cli/mcp). + +| Subcommand | Arguments | +| --- | --- | +| `list` | `--json`, `--all`. Alias `ls`. | +| `get <name>` | `--json` | +| `add <name>` | `-f/--force`, `--allow-local`, `--env KEY=VALUE`, `--url <URL>`, `--bearer-token-env-var <ENV_VAR>`, `--sse <URL>`, `--sse-bearer-token-env-var <ENV_VAR>`, or `-- <command>...` for a local server | +| `remove <name>` | `-y/--yes`. Alias `rm`. | +| `enable <name>` / `disable <name>` | Turn a server on or off | +| `rename <old> <new>` | Rename a server | +| `auth [name]` | Authorise a server. Subcommand `list`. | +| `logout [name]` | `--all` | +| `debug <name>` | `--json`, `--test-auth`, `--timeout`, `--no-cache`, `--show-cache-info` | + +## Plugins + +`cortex plugin` manages plugins. Alias `plugins`. See [CLI plugins](/cli/plugins). + +| Subcommand | Arguments | +| --- | --- | +| `list` | `--json`, `--enabled`, `--disabled`. Alias `ls`. | +| `install <name>` | `--version`, `-f/--force`, `--json`, `--accept-command <SHA256>`, `--trust-code`. Alias `add`. | +| `show <name>` | `--json`. Alias `info`. | +| `enable <name>` / `disable <name>` | Turn a plugin on or off | +| `remove <name>` | `-y`. Aliases `rm`, `uninstall`. | +| `update <name>` | `--source`, `--accept-command <SHA256>`, `--json` | +| `trust <name>` | `--yes` | +| `run <name>` | A command name, or `--tool <name>` with `--input <JSON>`. `--json`. | +| `search <query>` / `browse` | `--json` | +| `new <name>` | `-d`, `-a/--author`, `-o/--output`, `--advanced`. Alias `create`. | +| `dev` | `-p/--path`, `-w/--watch`, `--debounce-ms` | +| `build` | `-p/--path`, `--debug`, `-o/--output` | +| `validate` | `-p/--path`, `--json`, `-v`. Alias `check`. | +| `publish` | `-p/--path`, `--dry-run`, `-o` | + +## Editor integration + +`cortex acp` starts an Agent Client Protocol server so an editor can drive a session. Standard input and output is the only transport: run `cortex acp --stdio`. Alongside it you can pass `-C/--cwd`, `-v/--verbose` and `-m/--model`. A nonzero `-p/--port` or a `--host` other than the default fails closed with `ACP network transport is unsupported; use --stdio`, and `--agent`, `--allow-tool` or `--deny-tool` fail with `ACP agent selection and tool allow/deny controls are not supported`. Both checks run before the server starts. See [Editors](/cli/editor). + +## Configuration + +| Command | Description | +| --- | --- | +| `cortex config` | Show configuration. `--json`, `--edit`. Subcommands `get <key>`, `set <key> <value>`, `unset <key>`. | +| `cortex models [PROVIDER]` | List models. `--json`. Subcommand `list` with `--limit`, `--offset`, `--sort`, `--full`. | +| `cortex features list` | Inspect feature flags. | +| `cortex init` | Write `AGENTS.md` in the current directory. `-f/--force`, `-y/--yes`. | + +See [Configuration](/cli/configuration) for the file format and [Environment variables](/cli/environment-variables) for what the binary reads from the environment. + +## Utilities + +| Command | Description | +| --- | --- | +| `cortex github` | Repository integration. Alias `gh`. Subcommands `install`, `run`, `status`, `uninstall`, `update`. | +| `cortex pr <NUMBER>` | Check out a pull request. `-p/--path`, `-b/--branch`, `-F/--force`, `--info`, `--diff`, `--comments`, `--token`. | +| `cortex scrape <URL>` | Fetch a page as markdown, text or HTML. `-o/--output`, `-f/--format`, `--method`, `-t/--timeout`, `--retries`, `--user-agent`, `-H/--header`, `--cookie`, `--no-follow-redirects`, `--no-images`, `--no-links`, `--selector`, `--xpath`, `--pretty`. | +| `cortex stats` | Usage statistics. `-d/--days`, `-p/--provider`, `-m/--model`, `--json`, `-v`. | +| `cortex completion [SHELL]` | Shell completions for `bash`, `elvish`, `fish`, `powershell`, `zsh`. `--install` writes them into place. | + +## Maintenance + +| Command | Description | +| --- | --- | +| `cortex upgrade [VERSION]` | Update the CLI. `-c/--check`, `--changelog`, `-f/--force`, `-y/--yes`, `--channel`, `--pre`. | +| `cortex uninstall` | Remove the CLI. `-c/--keep-config`, `-d/--keep-data`, `--dry-run`, `-f/--force`, `-y/--yes`, `--backup`, `-p/--purge`. | +| `cortex compact` | Compaction and cleanup. Aliases `gc`, `cleanup`. Subcommands `run`, `logs`, `vacuum`, `status`, `config`. | +| `cortex cache` | Cache management. Subcommands `show`, `clear`, `size`, `list`. | +| `cortex logs` | Read logs. `-n`, `-f/--follow`, `-l/--level`, `-s/--session`, `--json`, `--paths`, `--clear`, `--keep-days`. | +| `cortex feedback [MESSAGE]` | Send feedback. Alias `report`. Subcommands `bug`, `good`, `bad`, `submit`, `history`. | +| `cortex alias` | Command aliases. Alias `aliases`. Subcommands `set`, `list`, `remove`, `show`. | + +## Diagnostics + +`cortex debug` groups the diagnostic commands. They are hidden from the main help, and they are supported: use them when you need to know what the CLI actually resolved rather than what you think it resolved. + +| Subcommand | Reports | +| --- | --- | +| `config` | Resolved configuration. `--json`, `--env`, `--diff`. | +| `paths` | Where everything is on disk | +| `system` | Platform and environment details | +| `file <path>` | How a file resolves | +| `skill <name>` | How a skill resolves | +| `lsp` | Language server status | +| `ripgrep` | Search backend status | +| `snapshot` | Workspace snapshots. `--create`, `--restore`, `--snapshot-id`, `--description`, `--json`. | + +A few further subcommands exist for development of the CLI itself. They are hidden, undocumented and not part of the supported surface. If `cortex --help` on your build lists a command this page does not, check your version with `cortex --version` before relying on it. + +## Exit codes and output shapes + +`cortex exec` is the command to script against. Its exit codes, its `json` envelope and the streaming event shapes are on [Headless and scripting](/cli/headless), along with the rule that matters most for automation: parse the JSON, and treat the shape of human-readable text as something that can change between releases. + +## Related + +- [Headless and scripting](/cli/headless) +- [Slash commands](/cli/slash-commands) +- [Tools the agent uses](/cli/tools) +- [Configuration](/cli/configuration) +- [Environment variables](/cli/environment-variables) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/sessions.mdx b/cli/sessions.mdx index 78223ff..74bcdf2 100644 --- a/cli/sessions.mdx +++ b/cli/sessions.mdx @@ -1,30 +1,47 @@ --- title: "CLI sessions" sidebarTitle: "Sessions" -description: "Every interactive run is a session written to disk as you go — list, resume, rewind, fork, export, import, share, lock, and clean up." -keywords: ["resume", "fork", "rewind", "export", "share", "history"] +description: "Every interactive run is a session written to disk: list, resume, rewind, fork, export, import, share, protect and clean up" +icon: "clock-rotate-left" --- -Every interactive run is a session: the transcript, the tool calls, and the context Cortex built up along the way. Sessions are written to disk as you go, so you can close the terminal and pick the work back up later. The CLI also remembers the server-side Code session id for each workspace, so terminal turns continue the same coding session you see in the web app. +Every interactive run of the CLI is a **session**: the transcript, the tool calls, and the context Cortex built up along the way. Sessions are written to disk as the work happens, so closing the terminal does not lose anything and you can pick the work back up later. The CLI also remembers which coding session belongs to which workspace, so a terminal turn continues the same work you see in the web app. -## Listing +This page covers the commands that act on sessions from your shell, the in-session commands that act on the one you are in, rewinding and forking, export and import, sharing a link, protecting a session from cleanup, and where the files live. + +## Six commands from the shell + +| Command | What it does | +| --- | --- | +| `cortex sessions` | List sessions | +| `cortex resume [SESSION_ID]` | Open one again | +| `cortex export [SESSION_ID]` | Write one out as a file | +| `cortex import <FILE_OR_URL>` | Read one back in | +| `cortex delete <SESSION_ID>` | Delete one | +| `cortex lock [SESSION_ID]` | Protect one from cleanup | + +<Note> +Rewinding, forking and sharing are things you do **inside** a session, with `/rewind`, `/fork` and `/share`. There is no `cortex rewind`, `cortex fork` or `cortex share` command, and the `--share` flag on `cortex run` is declared but refused: it stops the run with `--share is not supported by the Code service contract. No turn was submitted.` +</Note> + +## List sessions ```bash cortex sessions ``` -By default this shows sessions started in the current directory. +By default this shows the sessions started in the current directory. | Flag | Effect | | --- | --- | | `--all` | Include sessions from other directories | -| `--days <N>` · `--since <date>` · `--until <date>` | Filter by date | -| `--favorites` | Only favourites | -| `-s`, `--search <TEXT>` | Match on title or id | -| `-l`, `--limit <N>` | Cap the list | -| `--json` | Machine-readable | +| `--days`, `--since`, `--until` | Filter by date | +| `--favorites` | Only the ones you marked | +| `-s`, `--search` | Match on title or id | +| `-l`, `--limit` | Cap the number of rows | +| `--json` | Machine-readable output | -## Resuming +## Resume ```bash cortex resume # pick from recent sessions @@ -34,52 +51,59 @@ cortex resume <SESSION_ID> # a specific session cortex resume --all # do not filter the picker by directory ``` -Inside the TUI, `/resume [session-id]` does the same, and **Ctrl+S** or **Ctrl+O** opens the sessions panel: +`--no-session` is declared on the same command but cannot be combined with it: resuming with it set fails with `--no-session is incompatible with resume`. Treat it as a flag for the [command reference](/cli/reference) rather than a daily control. + +The picker lists recent sessions with what each one was about; typing filters the list, and the footer strip at the bottom of the screen names the keys that apply to it, including starting a new session instead. Inside a running session, `/resume` opens the same picker and `Ctrl+r` searches past sessions. + +Non-interactive runs can continue a session too: `cortex run --continue` picks up the most recent one and `cortex run --session <SESSION_ID>` continues a named one. A [goal](/cli/goal) comes back with the session it belongs to. + +## Start fresh, or clear the conversation -<Frame caption="/resume: type to search; each row shows the title, age, message count, and branch. Enter resumes, f favourites, d deletes."> - <img src="/images/cli/runtime/120x40/resume-picker.png" alt="Cortex CLI resume picker listing recent sessions" /> -</Frame> +`/new` starts a new session without leaving the TUI. `/clear` empties the conversation but keeps the session you are in; it asks first and tells you what is dropped and what is kept, because your files and your configuration are untouched either way. -`cortex run --continue` continues the most recent session non-interactively; `cortex run --session <ID>` continues a specific one. A persisted [goal](/cli/goal) comes back with the session. +`/session` prints the details of the session you are in, `/rename` gives it a name, and `/timeline` shows its timeline. `/favorite` and `/unfavorite` mark and unmark it, and `f` toggles the mark on the selected row in the sessions panel. -## Starting fresh +## Rewind, undo, fork -`/new` starts a new session without leaving the TUI. `/clear` empties the conversation but keeps the session — it asks first, and says exactly what is dropped and what is kept. +Press `Esc` twice in quick succession to open the rewind overlay, which walks back through the session to an earlier point. The overlay has its own keys and lists them while it is open. -<Frame caption="/clear: the transcript is dropped; git, files, and config stay as they are."> - <img src="/images/cli/runtime/120x40/clear-confirm.png" alt="Cortex CLI clear-conversation confirmation with Yes, clear and No, keep it" /> -</Frame> +From the composer: -## Rewinding and forking +- `/rewind` optionally takes a number of steps. +- `/undo` and `/redo` step the last action back and forward. +- `/fork` starts a new session from this one, optionally with a name, leaving the original as it was. +- `/ghost` manages ghost commits for undo. -Press **Esc** twice quickly to open the rewind overlay. Use **←** / **→** to pick an earlier point, then **Enter** to roll back to it, **f** to fork a new session from it, or **Esc** to cancel. `/rewind [steps]`, `/undo`, and `/redo` cover the same ground from the composer; `/fork [name]` forks the current session. +Forking is the safe way to try a second approach: the fork carries the conversation so far, and anything you do in it stays out of the original. -## Exporting +## Export ```bash -cortex export # most recent session -cortex export <SESSION_ID> -o out.json -cortex export <SESSION_ID> -f yaml # json (default), yaml, or csv -cortex export <SESSION_ID> --pretty +cortex export # the most recent session +cortex export <SESSION_ID> -o out.json # choose the output path +cortex export <SESSION_ID> -f yaml # json, yaml or csv +cortex export <SESSION_ID> --pretty # readable formatting ``` -From the TUI, `/export` offers Markdown, JSON, or plain text and writes `cortex_<title>_<date>.<ext>` to your documents or home directory. Markdown exports keep the model's reasoning in a collapsed details block when present. +From inside a session, `/export` offers Markdown, JSON or plain text and writes a file named in the pattern `cortex_<title>_<date>.<ext>`. -## Importing +## Import ```bash cortex import session.json -cortex import https://example.com/session.json -cortex import - # from stdin -cortex import session.json --force # overwrite an existing session -cortex import session.json --resume # import and open it +cortex import https://cortex.foundation/a-session.json +cortex import - # read from standard input +cortex import session.json --force # overwrite an existing session +cortex import session.json --resume # import it and open it ``` -## Sharing +Import is how a session moves between machines, and with `-` it composes with anything that can write JSON to a pipe. -`cortex run --share` shares the session on completion and prints the URL. In the TUI, `/share [duration]` creates a link; durations read `30d`, `24h`, `60m`, or `never`. +## Share a link -## Protecting sessions from cleanup +`/share` creates a link to the session. It takes a duration, and the values it accepts are `30d`, `24h`, `60m` and `never`. Sharing is an in-session action only: `cortex run --share` is refused before the run starts. + +## Protect a session from cleanup ```bash cortex lock add <SESSION_ID> -r "reference for the migration" @@ -88,33 +112,42 @@ cortex lock check <SESSION_ID> cortex lock remove <SESSION_ID> ``` -Locked sessions survive `cortex compact` and `cortex delete`. +`cortex lock` is also available as `cortex protect`. A locked session survives the cleanup commands below, which makes it the right thing to do to the session you will want to point at in three months. The reason you give with `-r` is there so the lock explains itself later. -## Deleting and cleaning up +## Delete and clean up ```bash -cortex delete <SESSION_ID> # asks first -cortex delete <SESSION_ID> --yes - -cortex compact status # what cleanup would reclaim -cortex compact run --dry-run -cortex compact run # compact logs, sessions, history -cortex compact vacuum --session-days 30 -cortex compact logs --keep-days 7 +cortex delete <SESSION_ID> # asks first +cortex delete <SESSION_ID> --yes # do not ask ``` -`cortex cache` manages the model, response, and update caches separately; `cortex logs` reads and prunes log files. +`-y/--yes` skips the confirmation, and `-f/--force` is accepted as well. Housekeeping across everything the CLI has written is a separate command, `cortex compact`, also available as `cortex gc` and `cortex cleanup`: -## Titles and favourites +```bash +cortex compact status # what cleanup would reclaim +cortex compact run # compact logs, sessions and history +``` -`/rename <name>`, `/favorite`, `/unfavorite`. `/session` prints the current session's details; `/timeline` shows its timeline. +It also takes `logs`, `vacuum` and `config` subcommands. ## Where sessions live -`~/.cortex/sessions/` by default, with `goal.json` beside a session that has a goal, and `~/.cortex/code-sessions.json` mapping each workspace to its Code session id. `cortex debug paths` prints the real locations on your machine. See [Configuration → Data locations](/cli/configuration#data-locations). +Sessions are files under the Cortex home directory, one directory per session at `~/.cortex/sessions/{session-id}/`. A session with a goal keeps it alongside as its own file, which is why a goal survives resuming and compaction. `~/.cortex/code-sessions.json` is the map from a workspace to the coding session it belongs to. + +Two configuration keys govern the history file: + +```toml +[history] +persistence = "save-all" # or "none" to keep no history +max_bytes = 10000000 +``` + +Setting `persistence` to `none` is the way to run without a stored history at all. See [Data locations](/cli/data-locations) for everything the CLI writes and [Configuration](/cli/configuration) for where to set these. ## Related -- [Goals](/cli/goal) -- [Headless runs](/cli/headless) — continuing a session across `cortex exec` invocations. -- [Code sessions](/code/sessions) — the same sessions in the web app. +- [Goals](/cli/goal) - the objective that rides along with a session +- [The TUI](/cli/tui) - the sessions panel, the resume picker and the rewind overlay +- [Headless and one-shot runs](/cli/headless) - continuing a session from a script +- [Data locations](/cli/data-locations) - what is on disk, and what `cortex compact` reclaims +- [Code sessions](/code/sessions) - the same work in the web app diff --git a/cli/sign-in.mdx b/cli/sign-in.mdx index 965b00e..0b7cb28 100644 --- a/cli/sign-in.mdx +++ b/cli/sign-in.mdx @@ -1,94 +1,122 @@ --- -title: "Sign in" -description: "cortex login opens the browser flow; a device code covers machines without one; API keys cover CI. Credentials live in your OS keyring." -keywords: ["login", "authentication", "API key", "device code", "token"] +title: "Sign in to the CLI" +sidebarTitle: "Sign in" +description: "Sign in to Cortex CLI from a browser, with a device code, through single sign-on, or with an API key for unattended runs" +icon: "right-to-bracket" --- -The CLI uses the same Cortex account as the web app. Sign in once per machine; the session is stored in your operating system's keyring. +The CLI signs in with your Cortex account, the same one the web and desktop apps use. You sign in once per machine and the CLI keeps the session in your operating system's credential store, so you do not repeat it for every project. -## Browser sign-in (default) +This page covers the interactive sign-in, the device-code route for machines without a browser, single sign-on, the unattended options for scripts and pipelines, how to check who you are signed in as, how to sign out, and where credentials are kept. If you have not installed the CLI yet, start with [Install the CLI](/cli/install). + +## Sign in from a browser ```bash cortex login ``` -Cortex prints a verification URL and opens it in your browser. Approve the sign-in there and the CLI picks up the session. From inside the TUI, `/login` does the same without leaving your session; the inline screen offers **Continue with browser** or **Paste an API key**. +A sign-in page opens in your browser. Approve it there and the CLI continues on its own. Confirm the result with `cortex whoami`. + +From inside a session, `/login` does the same thing without leaving the session. The inline sign-in screen offers exactly two rows, **Continue with browser** and **Paste an API key**. There is no guest row and no exit row: pick one of the two, or press **Esc**. + +While the CLI is waiting it shows `Waiting for browser authentication…`. On success it prints `Signed in as ...`. If the attempt expires, is refused, or the credential store rejects the write, it prints `Sign-in didn't complete` and you can run `cortex login` again. -<Frame caption="The inline sign-in picker: Continue with browser, or Paste an API key. Numbered rows, arrow keys to select, Enter to confirm."> - <img src="/images/cli/runtime/120x40/login.png" alt="Welcome to Cortex CLI — How would you like to log in? Continue with browser or Paste an API key" /> -</Frame> +## Sign in on a machine without a browser -## A machine without a browser +For a server, a container, or a remote shell: ```bash cortex login --device-auth ``` -Cortex prints a short code and a URL. Open the URL on any device that has a browser, enter the code, and the CLI continues when the sign-in is approved. Good for servers, containers, and remote shells. +The CLI prints a short code, for example `Your code WXYZ-1234`, along with the address to visit. Open that address on any device that does have a browser, enter the code, and approve the sign-in. The CLI picks the session up as soon as you have approved it. + +## Single sign-on + +```bash +cortex login --sso +``` + +Use this when your organization signs in through single sign-on. The web sign-in dialog offers the same route, labelled **Single sign-on (SSO)**. -<Frame caption="Waiting for the browser: the code to enter, and the URL to visit if the browser did not open. Esc cancels."> - <img src="/images/cli/runtime/120x40/login-waiting.png" alt="Waiting for browser authentication with a device code shown" /> -</Frame> +## Unattended runs and CI -## Unattended use: API key or token +Do not use the browser flow in a pipeline. There is no browser to open and, on most runners, no credential store to write to, so `cortex login` on its own cannot complete. -For CI and other unattended runs, do not use the browser flow. +Read the secret from standard input so it never reaches your shell history or the process list: ```bash -# read an API key from stdin — never from the command line +# an API key on stdin printf '%s' "$CORTEX_API_KEY" | cortex login --with-api-key -# or pass a token your CI secret store populates +# or a token your secret store populates cortex login --token "$CORTEX_AUTH_TOKEN" ``` -Or skip `cortex login` entirely and set the variable for the job: +Or skip `cortex login` altogether and set a variable for the job: | Variable | Purpose | | --- | --- | -| `CORTEX_API_KEY` | API key for headless and CI use | -| `CORTEX_AUTH_TOKEN` | A session or bearer token | -| `CORTEX_API_URL` | The API base URL, if your deployment differs from `https://api.cortex.foundation` | - -Take the value from your CI secret store. Never write it into a workflow file or commit it. +| `CORTEX_API_KEY` | An API key, for headless and unattended use | +| `CORTEX_AUTH_TOKEN` | A session or bearer token. Checked before `CORTEX_API_KEY` | +| `CORTEX_API_URL` | The API base URL, when your deployment differs from the default | -## Enterprise SSO +The CLI resolves credentials in this order: `CORTEX_AUTH_TOKEN` first, then `CORTEX_API_KEY`, and the credential `cortex login` stored last. An environment variable therefore wins over a stored sign-in, which is what makes a runner predictable, and what to check first when a machine keeps acting as an account you did not expect. -`cortex login --sso` is available for organisations that sign in through single sign-on. The web app's sign-in dialog offers the same **Single sign-on (SSO)** route. +<Warning> +Take the value from your secret store at run time. Never write a key or a token into a workflow file, a configuration file, or a commit. +</Warning> -## Check and sign out +## Check the state, and sign out ```bash -cortex whoami # the signed-in account +cortex whoami # the account you are signed in as cortex login status # the state of the stored session -cortex logout # asks first -cortex logout --yes -cortex logout --all # every stored credential +cortex logout # asks for confirmation first +cortex logout --yes # no confirmation +cortex logout --all # remove every stored credential ``` -In the TUI: `/account` (aliases `/whoami`, `/me`), `/login`, `/logout`. +Inside a session the equivalents are `/account` (aliases `/whoami` and `/me`), `/login` and `/logout`. -## Where credentials are stored +## Where credentials are kept + +Sign-in writes to your operating system's credential store, under the service name `cortex-cli` and the account name `auth`. | Platform | Store | | --- | --- | | macOS | Keychain | -| Linux | Secret Service — GNOME Keyring, KWallet, and compatible providers | +| Linux | Secret Service, such as GNOME Keyring or KWallet | | Windows | Credential Manager | -Credentials are deliberately **not** written to a plaintext file in your home directory, and never into the repository. If no keyring is available — a bare container, a headless CI runner — use `CORTEX_API_KEY` or `CORTEX_AUTH_TOKEN` instead of trying to make one work. - -## Troubleshooting - -| Symptom | Cause | Fix | -| --- | --- | --- | -| *The coding service is temporarily unavailable* during sign-in | The CLI could not reach `api.cortex.foundation` | Check network access and proxies. The message is deliberately the whole story — Cortex does not surface provider or transport names. | -| Sign-in succeeds but `cortex whoami` fails | The keyring did not persist the session | On Linux, check that a Secret Service provider is running; otherwise fall back to `CORTEX_API_KEY` | -| A CI job cannot sign in | It tried the browser flow | Use `--with-api-key`, `--token`, or set `CORTEX_API_KEY` in the job environment | -| The TUI asks you to sign in again | The stored session expired or was cleared | `cortex login` | +Credentials are deliberately not written to a plaintext file in your home directory, and never into the repository you are working in. The session material the CLI does keep in its own home directory carries no secrets. + +<Note> +If no credential store is available, a bare container or a headless runner for instance, use `CORTEX_API_KEY` or `CORTEX_AUTH_TOKEN` rather than trying to make a store work. +</Note> + +## When sign-in does not work + +<AccordionGroup> + <Accordion title="The coding service is temporarily unavailable"> + The CLI could not reach `api.cortex.foundation`. Check network access and any proxy in front of it, then try again. This message is deliberately the whole story: the CLI does not surface provider, SDK or transport names, so there is no extra detail hiding behind it. + </Accordion> + <Accordion title="Sign-in appears to succeed, but cortex whoami fails"> + The credential store did not persist the session. On Linux, check that a Secret Service provider is actually running in your session; over SSH or in a minimal desktop there often is not one. Otherwise fall back to `CORTEX_API_KEY`. + </Accordion> + <Accordion title="A job in CI cannot sign in"> + It tried the browser flow. Use `cortex login --with-api-key` or `cortex login --token`, or set `CORTEX_API_KEY` in the job environment and skip `cortex login` entirely. + </Accordion> + <Accordion title="The CLI asks you to sign in again"> + The stored session expired or was cleared. Run `cortex login` again. If it keeps happening on the same machine, the credential store is probably not persisting between runs; the two checks above apply. + </Accordion> +</AccordionGroup> ## Related -- [Install](/cli/install) -- [Configuration](/cli/configuration) — every environment variable the CLI reads. -- [Accounts](/getting-started/accounts) — what a signed-in account unlocks everywhere. +- [Install the CLI](/cli/install) +- [CLI quickstart](/cli/quickstart) +- [Environment variables](/cli/environment-variables) +- [Data locations](/cli/data-locations) +- [Accounts](/getting-started/accounts) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/skills.mdx b/cli/skills.mdx new file mode 100644 index 0000000..e71e80b --- /dev/null +++ b/cli/skills.mdx @@ -0,0 +1,127 @@ +--- +title: "Skills in the CLI" +sidebarTitle: "Skills" +description: "Teach the CLI a procedure once: what a skill file contains, where the CLI looks for it, how the agent loads it, and how to gate one" +icon: "graduation-cap" +--- + +A skill is a bundle of instructions the agent can load on demand. Where an agent defines *who* is working, a skill defines *how* a particular job is done: your deployment checklist, your migration procedure, the way your team writes commit messages. Writing one is how you stop repeating the same briefing at the start of every session. + +Skills are loaded through the `UseSkill` tool, so the agent pulls one in when it decides the task calls for it, rather than carrying every procedure in its context all the time. This page covers the skills the CLI ships with, how to write your own, the order the CLI searches for them, the commands for listing and invoking one, and how to require approval before a skill runs. + +## The skills that ship with the CLI + +| Skill | Covers | +| --- | --- | +| `git` | Git operations | +| `code-quality` | Quality and style checks | +| `file-operations` | Working with files safely | +| `debugging` | Systematic debugging | +| `security` | Security review | +| `planning` | Planning work | + +## Write a skill + +A skill is a directory containing `SKILL.md`: YAML frontmatter, then the instructions as markdown. + +```markdown +--- +name: release-checklist +description: Use when cutting a release. Runs the pre-release checks in order and stops at the first failure. +args: + - name: version + description: The version being released + required: true + - name: channel + description: Release channel + default: stable +tools: + - Read + - Grep + - Execute +--- + +1. Confirm the working tree is clean. +2. Run the test suite and stop at the first failure. +3. Check that the changelog has an entry for the version being released. +4. Tag the release on the requested channel. +``` + +The frontmatter fields: + +| Field | Type | Notes | +| --- | --- | --- | +| `name` | string | Lowercase letters, digits and hyphens, up to 64 characters | +| `description` | string | Up to 1024 characters. This is what the agent matches against | +| `args` | list | Each entry has `name`, `description`, and optionally `required` and `default` | +| `tools` | list | Restrict the agent to these tools while the skill is active | +| `version`, `author`, `tags` | | Metadata | + +`description` is the field that decides whether a skill ever gets used. Write it as the situation it applies to, not as a title. The tool names in `tools` are the case-sensitive ones from [Tools the agent uses](/cli/tools); an explicit list is exact, so a skill that only reads and greps cannot edit a file while it is active. + +<Note> +Nothing verifies who wrote a skill, and a skill shapes what the agent does with your repository. Read one before you drop it into a project. The CLI checks a SHA-256 checksum for its own release downloads, and even there a checksum detects corruption rather than independent publisher identity: checksums are not signatures. +</Note> + +## Where the CLI looks + +Skills are searched in this order, so a project can override a personal skill of the same name: + +1. Built-in skills +2. `./SKILL.md` in the working directory +3. `<project>/.agents/<name>/SKILL.md` +4. `<project>/.agent/<name>/SKILL.md` +5. `<project>/.cortex/skills/<name>/SKILL.md` +6. `~/.cortex/skills/<name>/SKILL.md` + +A `<dir>/<name>.md` file is also accepted, and subdirectories are scanned for `SKILL.md`. When the same name exists at more than one level, project files take priority. + +The picker labels each skill with the level it came from, and there are only two words for it: **project** and **user**. A skill you want a teammate to have should be committed to the repository, so it resolves as a project skill on their machine too. + +## Use a skill + +The agent invokes skills itself through the `UseSkill` tool; the slash commands are for when you want to force the issue. + +| Command | Effect | +| --- | --- | +| `/skills` | List the available skills | +| `/skill <name> [args...]` | Invoke one directly | +| `/skill-reload` | Re-read skills from disk after editing one | + +`/skills` opens a filter-as-you-type panel. It prompts with `Type to search skills`, and each row is the skill name, its one-line description, and its level: + +``` +> release-notes Draft release notes from the git log · project + pdf-report Render a PDF from a markdown report · user + db-migrate Write and verify a schema migration · project +``` + +Those three are shapes, not skills you will find on a fresh install. The footer of that panel is: + +``` + Enter:run | r:reload | Esc:close +``` + +So `r` picks up a `SKILL.md` you have just edited without restarting the session, which is the loop you want while you are writing one. + +From a shell, `cortex debug skill <name>` shows how a skill resolves, which is the quickest way to find out why the wrong copy of a skill is winning. + +## Require approval before a skill runs + +Skills go through the permission table like any other capability: + +```toml +[permission.skill] +"release-checklist" = "ask" +"*" = "allow" +``` + +`ask` prompts you before that skill is loaded, which is worth setting on anything that touches a release or a migration. See [Permission policy](/cli/policy) for where that table lives and how a project file overrides your own. + +## Related + +- [Agents and subagents](/cli/agents) +- [Tools the agent uses](/cli/tools) +- [Permission policy](/cli/policy) +- [Slash commands](/cli/slash-commands) +- [CLI plugins](/cli/plugins) diff --git a/cli/slash-commands.mdx b/cli/slash-commands.mdx index 2504a7b..9966aa9 100644 --- a/cli/slash-commands.mdx +++ b/cli/slash-commands.mdx @@ -1,116 +1,147 @@ --- title: "Slash commands" -description: "Everything you can type after / in the Cortex CLI composer — model, mode, permissions, plan, goal, sessions, files, MCP, diagnostics — and how to add your own." -keywords: ["commands", "/help", "/model", "/goal", "palette"] +description: "Every built-in command you can type after / in the Cortex CLI composer, grouped by purpose, plus aliases and your own project commands" +icon: "bolt" --- -Type `/` in the composer to open the command list. It shows the most-used commands first and filters as you type; the trailer *N more — keep typing to filter* means there is more below. A line beginning with `/` that is not a known command is sent to the agent as an ordinary message. - -<Frame caption="The slash palette after typing /: model, mode, permissions, plan, goal, effort, mcp, sandbox — and “13 more — keep typing to filter”."> - <img src="/images/cli/runtime/120x40/slash-palette.png" alt="Cortex CLI slash command palette showing /model, /mode, /permissions, /plan, /goal, /effort, /mcp, /sandbox" /> -</Frame> - -## The palette home - -These are the commands the palette shows first: - -| Command | What it does | -| --- | --- | -| `/model` | Choose the model for this session and its reasoning effort — Low, Medium, High | -| `/mode` | Switch between **Agent**, **Plan**, and **Ask** | -| `/permissions` | Set the approval policy — **Read-only**, **Smart**, or **Full access** | -| `/plan` | Draft a plan before writing any code | -| `/effort` | Tune reasoning effort for the current model | -| `/goal` | Set, show, pause, resume, or clear a persisted long-horizon objective. See [Goals](/cli/goal) | -| `/mcp` | View and manage MCP servers | -| `/sandbox` | Configure sandboxed command execution | -| `/usage` | Plan usage, quota, and limits | -| `/resume` | Resume a previous session | -| `/jobs` | Background work — Cloud hand-offs, subagents, and queued follow-ups (`/tasks` is the older name) | -| `/skills` | List and manage skills | -| `/btw` | Ask a side question while a turn runs — answered without touching the running turn | -| `/compact` | Toggle the compact display | -| `/clear` | Clear the current conversation | -| `/diff` | Show a file diff | -| `/copy` | How to copy text out | -| `/config` | Show configuration | -| `/login` · `/logout` | Sign in, or clear stored credentials | -| `/settings` | Open the settings panel | -| `/interrupt` | Stop the running turn (same as **Esc**) | - -Keep typing to filter — `/model` narrows the list to the commands that match: - -<Frame caption="Filtering the palette: /model matches /model, /mode, /mcp-reload, and /custom-commands."> - <img src="/images/cli/runtime/120x40/slash-model-typed.png" alt="Cortex CLI slash palette filtered by typing /model" /> -</Frame> +Type `/` in the composer and the command list opens, filtering as you type. Slash commands are how you reach everything the terminal app does that is not a message to the agent: sessions, model and policy, files, MCP servers, diagnostics, your account. A line beginning with `/` that is **not** a known command is not an error; it is sent to the agent as an ordinary message. + +This page lists the built-in commands, grouped the way the in-app list groups them, with their aliases and their arguments. Most of them are also reachable another way, and several are usually reached by their alias rather than their full name: `/tasks` as `bg`, `/models` as `m`, `/shortcuts` as `keys`. At the end are the rules for adding commands of your own to a project. + +<Note> +Arguments in angle brackets are required and arguments in square brackets are optional, exactly as the in-app list shows them. A long list ends with a trailer such as `… 87 more — keep typing to filter`, so filtering is always the way through it. +</Note> + +## App, help and display + +| Command | Aliases | Usage | +| --- | --- | --- | +| `/help` | `h`, `?` | `/help [topic]` | +| `/shortcuts` | `keys` | Open the shortcuts sheet | +| `/settings` | `config`, `prefs` | Open the settings panel | +| `/reload-config` | `reload` | Re-read configuration from disk | +| `/theme` | | `/theme [name]` | +| `/compact` | | Toggle the compact display | +| `/palette` | `cmd` | Open the command palette | +| `/copy` | `cp` | How to copy text out | +| `/version` | `v` | Show version information | +| `/upgrade` | `update` | Check for and install updates | +| `/experimental` | `exp`, `features` | `/experimental [feature] [--enable\|--disable]` | +| `/cost` | | Token usage and cost | +| `/ratelimits` | `limits`, `quota` | Rate limits and usage | +| `/bug` | | `/bug [description]` | +| `/quit` | `q`, `exit` | Quit | + +## Agents, skills, plugins and hooks + +| Command | Aliases | Usage | +| --- | --- | --- | +| `/agents` | `subagents` | List and manage agents | +| `/delegates` | | `/delegates [action]` | +| `/tasks` | `bg`, `background` | Background tasks and agents | +| `/bg-process` | | `/bg-process [action] [target]` | +| `/skills` | `sk` | List and manage skills | +| `/skill` | `invoke` | `/skill <name> [args...]` | +| `/skill-reload` | `sr` | Reload skills from disk | +| `/plugins` | `plugin` | `/plugins [action] [plugin-id]` | +| `/hooks` | | `/hooks [action]` | +| `/commands` | `cmds` | List custom commands | +| `/custom-commands` | `cc` | `/custom-commands [action]` | + +Details are on [MCP servers in the CLI](/cli/mcp), [Skills in the CLI](/cli/skills), [Agents and subagents](/cli/agents), [Hooks](/cli/hooks) and [CLI plugins](/cli/plugins). + +`/hooks` is the exception in this group. It is accepted and its actions are validated, but nothing handles it in this build: it answers `Unsupported command in this session` and does nothing. Use `cortex plugin list` instead, and see [Hooks](/cli/hooks) for how a hook reaches a session at all. + +## Code and workflow + +| Command | Aliases | Usage | +| --- | --- | --- | +| `/init` | | `/init [--force]`, writes `AGENTS.md` | +| `/review` | | `/review [target] [--base=branch]` | +| `/multiedit` | `sed`, `replace` | `/multiedit <pattern> <replacement> [--glob=pattern]` | +| `/ghost` | | `/ghost [action]`, ghost commits for undo | +| `/spec` | | `/spec [off]`, toggle specification mode | +| `/goal` | | `/goal [objective\|status\|pause\|resume\|clear]` | +| `/ide` | | Manage IDE integration | +| `/install-github-app` | | Install the Cortex GitHub App | + +`/spec` is on [Plan and Spec modes](/cli/plan-mode) and `/goal` is on [Goals](/cli/goal). + +## Account, billing and usage + +| Command | Aliases | Usage | +| --- | --- | --- | +| `/login` | `signin` | Sign in | +| `/logout` | `signout` | Clear stored credentials | +| `/account` | `whoami`, `me` | Account information | +| `/billing` | `plan`, `subscription` | Billing status and credits | +| `/usage` | `stats`, `credits` | `/usage [--from YYYY-MM-DD] [--to YYYY-MM-DD]` | +| `/refresh` | `retry` | Refresh billing after adding a payment method | + +Signing in from the terminal, including on a machine with no browser, is covered on [Sign in to the CLI](/cli/sign-in). ## Session | Command | Aliases | Usage | | --- | --- | --- | | `/session` | `info` | Current session details | +| `/clear` | `cls` | Clear the conversation | | `/new` | `n` | Start a new session | -| `/clear` | `cls` | Clear the conversation, keep the session | | `/resume` | `r`, `load` | `/resume [session-id]` | -| `/sessions` | `list` | List sessions | +| `/sessions` | `list`, `ls-sessions` | List sessions | | `/fork` | `branch` | `/fork [name]` | | `/rename` | `mv` | `/rename <name>` | -| `/favorite` · `/unfavorite` | `fav`, `star` | Mark or unmark a favourite | -| `/export` | `save` | `/export [format]` — Markdown, JSON, or text | -| `/share` | | `/share [duration]` — `30d`, `24h`, `60m`, or `never` | -| `/timeline` | `tl` | The session timeline | +| `/favorite` | `fav`, `star` | Mark as favourite | +| `/unfavorite` | `unfav`, `unstar` | Remove the favourite mark | +| `/export` | `save` | `/export [format]`, Markdown, JSON or text | +| `/share` | | `/share [duration]`, for example `30d`, `24h`, `60m` or `never` | +| `/timeline` | `tl` | View the session timeline | | `/rewind` | `rw` | `/rewind [steps]` | -| `/undo` · `/redo` | `u` | Undo or redo the last action | +| `/undo` | `u` | Undo the last action | +| `/redo` | | Redo | | `/delete` | `rm` | `/delete [session-id]` | -Details: [Sessions](/cli/sessions). +<Warning> +`/share`, `/fork` and `/rewind` exist only inside a session. There is no `cortex share`, `cortex fork` or `cortex rewind` command on the command line; the one non-interactive equivalent is the `--share` flag on `cortex run`. The commands that do exist outside a session are listed on [Command reference](/cli/reference). +</Warning> + +## Navigation + +| Command | Aliases | Usage | +| --- | --- | --- | +| `/diff` | `d` | `/diff [file]` | +| `/transcript` | `tr` | View the transcript | +| `/history` | `hist` | Command history | +| `/scroll` | | `/scroll <top\|bottom\|n>` | +| `/goto` | `g` | `/goto <n>` | ## Files and context | Command | Aliases | Usage | | --- | --- | --- | | `/add` | `a`, `include` | `/add <file>...` | -| `/remove` | `exclude` | `/remove <file>...` | +| `/remove` | `rm-file`, `exclude` | `/remove <file>...` | | `/search` | `find`, `grep` | `/search <pattern>` | | `/ls` | `dir`, `files` | `/ls [path]` | | `/tree` | | `/tree [path]` | | `/mention` | `@`, `ref` | `/mention <file\|symbol>` | -| `/images` | `img` | `/images <file>...` | +| `/images` | `img`, `pics` | `/images <file>...` | | `/context` | `ctx` | Show the current context files | -| `/init` | | `/init [--force]` — write `AGENTS.md` | - -## Model and policy - -| Command | Usage | -| --- | --- | -| `/model [name]` | Pick a model; **Tab** cycles effort in the picker | -| `/effort` | The same effort radios | -| `/mode` | Agent, Plan, Ask | -| `/permissions` | Read-only, Smart, Full access | -| `/approval <ask\|session\|always\|never>` | Set the approval behaviour explicitly | -| `/sandbox [on\|off]` | Toggle sandboxed execution | -| `/auto [on\|off]` | Toggle auto-approval | -| `/spec [off]` | Toggle specification mode | -| `/temperature <0.0-2.0>` · `/tokens <n>` | Sampling controls | -Details: [Modes and permissions](/cli/modes-and-permissions). +Typing `@` in the composer opens the file picker directly, which is the quicker path for adding context mid-sentence. -## Agents, skills, tasks +## Model and policy | Command | Aliases | Usage | | --- | --- | --- | -| `/agents` | `subagents` | List and manage agents | -| `/delegates` | | `/delegates [action]` — manage subagents | -| `/jobs` | `tasks` | Background tasks and agents | -| `/skills` | `sk` | List and manage skills | -| `/skill` | `invoke` | `/skill <name> [args...]` | -| `/skill-reload` | `sr` | Reload skills from disk | -| `/plugins` | `plugin` | `/plugins [action] [plugin-id]` | -| `/hooks` | | `/hooks [action]` | -| `/commands` | `cmds` | List custom commands | -| `/custom-commands` | `cc` | `/custom-commands [action]` | +| `/model` | `models`, `m`, `lm`, `list-models` | `/model [name]` | +| `/approval` | `approve` | `/approval <ask\|session\|always\|never>` | +| `/sandbox` | `sb` | `/sandbox [on\|off]` | +| `/auto` | `autopilot` | `/auto [on\|off]` | +| `/temperature` | `temp` | `/temperature <0.0-2.0>` | +| `/tokens` | `max-tokens` | `/tokens <n>` | -Details: [Extend](/cli/extend). +`/model` and `/models` are the same command, so either spelling works, and `m` is the alias most people end up using. In the model list, `Tab` moves to the reasoning-effort controls and back; `/effort` is an alias that goes straight to them. Switching between Agent, Plan and Ask is `Shift+Tab` in the composer. What these controls actually permit is on [Modes and permissions](/cli/modes-and-permissions). ## MCP @@ -121,61 +152,40 @@ Details: [Extend](/cli/extend). | `/mcp-auth` | `auth` | MCP authentication | | `/mcp-reload` | | Reload MCP server configuration | -## Account and usage +## Diagnostics | Command | Aliases | Usage | | --- | --- | --- | -| `/login` · `/logout` | `signin`, `signout` | Sign in, or clear stored credentials | -| `/account` | `whoami`, `me` | Account information | -| `/billing` | `plan`, `subscription` | Billing status and credits | -| `/usage` | `stats`, `credits` | `/usage [--from YYYY-MM-DD] [--to YYYY-MM-DD]` | -| `/cost` | | Token usage and cost | -| `/ratelimits` | `limits`, `quota` | API rate limits and usage | -| `/refresh` | `retry` | Refresh billing after adding payment | - -<Frame caption="/usage: agent requests, tokens this month, and Cloud agent minutes against the plan's ceilings, with the renewal date."> - <img src="/images/cli/runtime/120x40/usage.png" alt="Cortex CLI /usage panel showing agent requests, tokens, and Cloud agent minutes" /> -</Frame> - -## Working with code - -| Command | Usage | -| --- | --- | -| `/diff [file]` | Show a diff | -| `/review [target] [--base=branch]` | Review changes | -| `/multiedit <pattern> <replacement> [--glob=pattern]` | Multi-file replace | -| `/ghost [action]` | Ghost commits for undo | -| `/bg-process [action] [target]` | Background processes | -| `/install-github-app` | Install the Cortex GitHub App | -| `/ide` | Manage IDE integration | - -## General and diagnostics - -| Command | Aliases | Usage | -| --- | --- | --- | -| `/help` | `h`, `?` | `/help [topic]` | -| `/version` | `v` | Version information | -| `/upgrade` | `update` | Check for and install updates | -| `/settings` | `prefs` | Open the settings panel | -| `/reload-config` | `reload` | Re-read configuration from disk | -| `/theme` | | `/theme [name]` | -| `/palette` | `cmd` | Open the command palette | -| `/experimental` | `exp`, `features` | `/experimental [feature] [--enable\|--disable]` | +| `/debug` | `dbg` | `/debug [on\|off]` | | `/status` | `stat` | Application status | | `/config` | `cfg` | `/config [key]` | | `/logs` | `log` | `/logs [level]` | -| `/debug` | `dbg` | `/debug [on\|off]` | -| `/diagnostics` | `diag`, `lint` | `/diagnostics [file]` | -| `/metrics` | `perf` | Performance metrics | | `/dump` | | `/dump [file]` | -| `/bug` | | `/bug [description]` — report a problem | -| `/quit` | `q`, `exit` | Quit | +| `/metrics` | `perf` | Performance metrics | +| `/diagnostics` | `diag`, `lint` | `/diagnostics [file]` | ## Your own commands -Add markdown files under `.cortex/commands/` in the project; `/commands` lists them. The file name is the command and the body is the prompt it sends. Project commands travel with the repository. +A project can carry its own commands. Put a markdown file in `.cortex/commands/` in the repository: the file name becomes the command and the body is the prompt it sends, so a command travels with the project and everyone working in it gets the same one. + +- `/commands` (alias `cmds`) lists the custom commands it found. +- `/custom-commands [action]` (alias `cc`) manages them. + +## If a command you read about is not there + +The list that opens when you type `/` is the built-in set for the version you are running. Guides, blog posts and older notes sometimes name commands that the current build does not have, and because an unknown `/` line is sent to the agent as a message, typing one looks like nothing happened except an odd prompt. Three cases worth knowing: + +- Switching mode is `Shift+Tab` in the composer. +- Specification mode is `/spec`. +- Approval behaviour is `/approval`, `/sandbox` and `/auto`. +- The model and its reasoning effort are both on the `/model` form, with `Tab` between them. + +When in doubt, type `/` and read the list, or open `cortex --help` outside the app. ## Related -- [The TUI](/cli/tui) · [Keyboard shortcuts](/cli/keyboard) -- The equivalents outside the TUI: `cortex --help` and `cortex <command> --help` +- [The TUI](/cli/tui): the composer, its sigils and the panels these commands open +- [CLI keyboard shortcuts](/cli/keyboard): what you can do without a command +- [CLI sessions](/cli/sessions): resume, fork, rewind, export and share in practice +- [Modes and permissions](/cli/modes-and-permissions): what the policy commands change +- [Command reference](/cli/reference): the commands and flags you type in your shell diff --git a/cli/themes.mdx b/cli/themes.mdx new file mode 100644 index 0000000..6893283 --- /dev/null +++ b/cli/themes.mdx @@ -0,0 +1,117 @@ +--- +title: "Themes" +description: "The four built-in CLI themes, the picker with live preview, and the configuration keys that control colour and the rest of the display." +icon: "palette" +--- + +The Cortex CLI ships four themes. A theme sets every colour the interface uses: timeline text, tool rows, borders, status lines and accents. Switching one is instant and reversible, so you can try all four in a live session before you decide. + +This page lists the four themes, shows the two ways to switch, gives the configuration keys for a theme and the related display settings, and prints the default palette in case you want a terminal profile that matches. Going beyond the four is covered under [Custom themes](#custom-themes) at the end. + +## The four themes + +The picker shows a display name, the configuration file uses a shorter id. Both refer to the same theme. + +| Theme | Config id | What it looks like | +| --- | --- | --- | +| **Cortex Night** | `dark` | `Default inky chrome · banner green on focus only`. The default. | +| **Cortex Day** | `light` | `Light chrome for bright rooms` | +| **Ocean Dark** | `ocean_dark` | `Deep blue and cyan accents`. `ocean` is accepted as a short form. | +| **Monokai** | `monokai` | `Classic code-editor colors` | + +There are exactly four, and none of them follows your terminal's light or dark setting: you pick a theme explicitly. If you move between a bright room and a dark one, switching is one command. + +## Switch a theme in a session + +| Command | Effect | +| --- | --- | +| `/theme` | Open the picker | +| `/theme monokai` | Switch straight to a theme by its config id | + +In the picker, `↑`/`↓` (or `k`/`j`) previews a theme live, so the whole interface repaints as you move down the list. `Enter` accepts the highlighted theme and `Esc` reverts to what you had, which makes trying one out free. + +The same control is in Settings. Press `F2` (or run `/settings`), open **Appearance** and expand the **Theme** row to reach `Appearance › Theme`. The selected theme carries a filled marker and the label `current`. In that submenu `↑/↓/j/k` navigate, `Enter` selects, `←` goes back up to Appearance, `d` resets the theme to the default, and `F2` or `Esc` closes Settings. + +<Note> +Whichever theme you pick, one rule does not move: `Themes never change the accent rule: banner green on focus only.` The accent marks the focused selection and nothing else, so a theme changes the palette without changing what the interface is telling you. +</Note> + +## Set a theme in configuration + +Set it once in `config.toml` and every new session starts with it: + +```toml +[tui.theme] +name = "ocean_dark" +``` + +Use the config id, not the display name. `/reload-config` picks up a change made on disk without restarting the session. [Configuration](/cli/configuration) covers where the file lives and how project and personal settings combine. + +## Other display settings + +Two more keys live next to the theme and change how much the interface moves and how loudly it speaks: + +```toml +[tui] +animations = true +notifications = true +``` + +`/compact` toggles a denser layout inside a session, which pairs well with a small terminal. For anything that is not the full interface, `--color auto|always|never` controls whether colour is emitted at all; use `--color never` when you are piping output into a file or a log. See [Headless and scripting](/cli/headless) for the rest of the non-interactive options. + +## The default palette + +These are the values the default theme uses. They are handy if you want your terminal profile, prompt or editor to sit next to the interface without clashing. + +| Role | Colour | +| --- | --- | +| Selection accent (the caret and the focused label, and the focused composer prompt) | `#1F4945` | +| Background | `#000000` | +| Charcoal panel (tips and info) | `#141414` | +| Past user turn bar | `#1C1C1C` | +| Selection bar | `#262626` | +| Hairline above and below the prompt, and around search fields | `#3A3A3A` | +| Focused border | `#525252` | +| Text | `#F5F5F5` | +| Dim text (placeholders, hints, descriptions) | `#6B7280` | +| Muted text | `#4B5563` | +| Success marks and diff additions (`+N`) | `#4ADE80` | +| Warning | `#FFC857` | +| Error, a stopped run, quota messages, a failed server | `#F87171` | +| Thinking status | `#6B7280` | + +Three rules explain why the palette looks the way it does: + +- The accent is the dominant background pixel of the Cortex banner, RGB `(31, 73, 69)`, which is `#1F4945`. +- The accent never outlines a box. Borders are grey, so a focused panel is legible without a coloured frame competing with the content. +- Focused green glyphs get a near-white backing rather than disappearing on black, and descriptions next to them stay dim. + +<Tip> +If you find an older screenshot or note that uses a gold accent, `#C9A95C`, it is stale. That colour is retired and no current theme uses it. +</Tip> + +## When colour looks wrong + +A theme can only work with what the terminal gives it. If colours look flat or text is hard to read after switching: + +- Check that your terminal advertises true colour. A 256-colour profile approximates the palette, so the accent and the dim greys move closer together. +- Try **Cortex Day** if you run a light terminal background. A dark theme on a light background is the usual cause of unreadable dim text. +- Press `d` on the Theme row in Settings to go back to the default, or run `/theme dark`. +- For output that is not the interface, remember that colour codes travel: `--color never` or a plain pipe destination gives you clean text. [CLI troubleshooting](/cli/troubleshooting) covers mangled output in more detail. + +## Custom themes + +A plugin can supply a theme: the plugin capability list includes themes, and a plugin can register a hook that overrides theme values. That is the supported extension point today, and it is described on [CLI plugins](/cli/plugins). + +<Note> +Pick one of the four built-ins, or ship a plugin that supplies a theme. Overriding individual palette roles by hand is not part of the documented surface for this build. +</Note> + +## Related + +- [The terminal interface](/cli/tui) +- [Configuration](/cli/configuration) +- [CLI plugins](/cli/plugins) +- [Slash commands](/cli/slash-commands) +- [Keyboard shortcuts](/cli/keyboard) +- [CLI troubleshooting](/cli/troubleshooting) diff --git a/cli/tools.mdx b/cli/tools.mdx new file mode 100644 index 0000000..d8195bd --- /dev/null +++ b/cli/tools.mdx @@ -0,0 +1,153 @@ +--- +title: "Tools the agent uses" +description: "The tools a CLI agent can call: reading, searching, editing, shell, language server, web, delegation, and how each call passes the sandbox and approval gates" +icon: "screwdriver-wrench" +--- + +Everything the agent does beyond talking is a **tool call**: reading a file, searching the repository, editing, running a command, asking a language server, fetching a page, delegating to a subagent. Each call shows up in the timeline as its own tile with the tool name, what it acted on and a result summary, so a session is auditable after the fact by scrolling back through it. + +This page is the inventory: what each tool does, what it takes, and the limits that apply. It also covers the two gates every call passes before it can change anything, how the available set narrows by context, and the tools that arrive from MCP servers and plugins. Tool names are **case-sensitive**: they are what you pass to `--enabled-tools` and `--disabled-tools`, and what you list in an agent's `tools` field. To see what a given run actually has, use `cortex exec --list-tools`. + +<Note> +These names belong to the CLI. Other Cortex products have their own tool sets, and a name here does not necessarily exist, or mean the same thing, on another surface. +</Note> + +## Two gates before anything changes + +When the agent calls a tool that could change your machine, two checks apply, in this order: + +1. The **sandbox** decides whether the operation is possible at all. Its modes run from read-only, through a workspace-write default, to full access. +2. The **approval policy** decides whether you are asked first. When it asks, a numbered prompt appears inline in the timeline and the turn waits for you. + +A `permission` table in your configuration overrides either one per capability, with `allow`, `ask` or `deny`, and it can be narrowed to a command pattern, a skill or a named MCP server. `Execute` is the tool these policies mainly exist for, because it is the one that runs commands in your shell. + +Where the tools run is a separate question from what they are allowed to do. Cloud is the default; This PC and SSH are opt-in and fail closed rather than silently falling back. See [Cloud, This PC, and SSH](/cli/hosts) and [Modes and permissions](/cli/modes-and-permissions). + +## Reading and searching + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `Read` | `file_path`, `offset`, `limit` | Read a file. `limit` defaults to 2400 lines | +| `LS` | `directory_path`, `ignorePatterns` | List a directory | +| `Grep` | `pattern`, `path`, `case_insensitive`, `line_numbers`, `context`, `context_before`, `context_after`, `glob_pattern`, `output_mode`, `head_limit` | Regex content search. `output_mode` is `file_paths` or `content` | +| `Glob` | `patterns`, `folder`, `exclude_patterns` | Find files by glob pattern | +| `SearchFiles` | `pattern`, `path`, `content_pattern` | Fuzzy file search | + +## Writing + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `Create` | `file_path`, `content` | Create a file, or overwrite one | +| `Edit` | `file_path`, `old_str`, `new_str`, `change_all` | Replace text in a file | +| `MultiEdit` | `edits` | Apply several edits atomically | +| `ApplyPatch` | `patch`, `dry_run` | Apply a unified diff | + +An edit tile in the timeline carries the line counts, in the form `● Edit … · +12 −3`, and expands to the diff so you can read the change rather than take it on trust. + +## Running commands + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `Execute` | `command`, `workdir`, `timeout` | Run a shell command. `command` is an argument array, not a string for a shell to parse | + +The default tool timeout is 900 seconds, and the configured command timeout defaults to 120 seconds. Both are settable; see [Configuration](/cli/configuration). + +## The web + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `WebSearch` | `query`, `num_results`, `category`, `include_domains`, `exclude_domains`, `use_neural`, `livecrawl`, `type`, `context_max_characters` | Search the web | +| `WebFetch` | `url`, `format`, `timeout` | Fetch a page. `format` is `text`, `markdown` or `html` | +| `FetchUrl` | `url`, `format`, `timeout` | Fetch a URL | + +Web search is enabled with `--search`. Search and deep research belong mainly to the chat surface, so do not assume they are in a CLI run's tool list; `cortex exec --list-tools` is the answer for a given run. + +## Language intelligence + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `LspDiagnostics` | `path`, `severity` | Diagnostics from the language server. `severity` is `error`, `warning` or `all` | +| `LspHover` | `file`, `line`, `column` | Hover information. Positions are 1-based | +| `LspSymbols` | `query`, `path` | Workspace symbol search | + +Diagnostics also arrive unprompted after an edit, as a tile such as `● Diagnostics src/…/composer.rs · 2` with one line per problem. + +## Planning, delegation and questions + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `Plan` | see [Plan and Spec modes](/cli/plan-mode) | Submit a structured plan for your approval | +| `UpdateGoal` | see [Goals](/cli/goal) | Record evidence-based progress against a goal | +| `ExitSpecMode` | `reason` | Leave specification mode, which unlocks the mutating tools | +| `Task` | `mode` (`explore`, `plan`, `worker`), `prompt`, `description`, `context`, `await_result` | Delegate to a subagent | +| `ListSubagents` | `include_custom` | List the available subagent types | +| `Questions` | `title`, `questions` | Ask you a structured question. Question types are `single`, `multiple`, `text` and `number` | + +## Task tracking + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `TodoWrite` | `todos` | Update the session todo list. Each item has an `id`, `content`, a `status` of `pending`, `in_progress` or `completed`, and a `priority` of `high`, `medium` or `low` | +| `TodoRead` | none | Read the current todo list | + +The list is visible in the timeline under delegated work, which is the quickest way to see what a long turn thinks it still has to do. + +## Skills and batching + +| Tool | Parameters | What it does | +| --- | --- | --- | +| `UseSkill` | `skill` | Load a skill into the context | +| `Batch` | `calls`, `timeout_secs`, `tool_timeout_secs` | Run between 1 and 10 tool calls in parallel. A `Batch` cannot nest another `Batch` or call the agent tools | + +Writing a skill of your own is on [Skills in the CLI](/cli/skills). + +## Tools from MCP servers and plugins + +Extensions add tools, and their names say where they came from: + +| Source | Naming | +| --- | --- | +| An MCP server | `mcp__<server>__<tool>` | +| A plugin | `plugin_<slug>` | + +An extension tool is not a privileged tool. It passes the same two gates as a built-in one, and the `permission` table can require approval for a named server or deny it outright. + +<Warning> +Nothing here is signed. Where Cortex verifies a download it compares a SHA-256 checksum taken from the same distribution origin as the file, which detects corruption, not independent publisher identity. Checksums are not signatures. Treat an extension as code you are choosing to run, and read what it does before enabling it. +</Warning> + +See [MCP servers in the CLI](/cli/mcp) and [CLI plugins](/cli/plugins). + +## What is available when + +The set is not fixed. It narrows with the context: + +- **Plan and Ask** withhold the mutating tools, and read-only agents are restricted to the reading tools. That block is enforced by the harness, not by asking the model to behave. +- **Specification mode** keeps the mutating tools locked until the plan is accepted and the agent calls `ExitSpecMode`. +- **A child task** cannot delegate further or put a question to you directly. Delegated work reports back through the parent that started it. +- **A headless run** can be narrowed with `--enabled-tools` and `--disabled-tools`. +- **The `permission` table** can require approval for, or deny, individual capabilities for everyone in a project. + +## Hooks can stop a tool call + +Hooks are declared by a plugin, in that plugin's manifest, and run around a plugin invocation. They do not fire around the tool calls an interactive session makes, so a hook is not the way to stop one. To forbid a tool call outright, use the `permission` deny list described above. + +<Warning> +A hook is never consent. A hook firing does not stand in for an approval, and it cannot grant one: the approval prompt still happens. A plugin hook may refuse an action, but it can never permit one. +</Warning> + +The events, the patterns that narrow them and which of them actually fire are on [Hooks](/cli/hooks). + +## There is no built-in browser or desktop automation + +Cortex ships no built-in browser tool and no desktop-automation tool. Browser work is done by connecting an MCP server that provides those tools, and they then pass the same authority boundary as any other call: the sandbox, the approval prompt and the `permission` deny list. `/browser` reports whether such a server is connected and names it; it never claims a capability the CLI does not have. + +The `Computer` concept is a different thing entirely. It selects *where* tools run, Cloud or This PC or SSH, and has nothing to do with controlling a browser or a desktop. See [Cloud, This PC, and SSH](/cli/hosts). + +## Related + +- [Modes and permissions](/cli/modes-and-permissions): the sandbox, the approval policy and the permission table +- [The TUI](/cli/tui): how tool tiles are drawn and how to expand one +- [Agents and subagents](/cli/agents): declaring a `tools` list for an agent of your own +- [Hooks](/cli/hooks): what a plugin hook may refuse, and which events fire +- [Headless and one-shot runs](/cli/headless): narrowing the tool set for an unattended run diff --git a/cli/troubleshooting.mdx b/cli/troubleshooting.mdx index d068b7c..bc8d1ee 100644 --- a/cli/troubleshooting.mdx +++ b/cli/troubleshooting.mdx @@ -1,111 +1,127 @@ --- title: "CLI troubleshooting" -description: "Start with four commands, then work through the messages — the coding service, hosts that refuse, the agent that will not edit, MCP, quotas, timeouts." -keywords: ["errors", "problems", "fixes", "not working"] +description: "Start with six commands, then work through the messages: service unavailable, hosts that refuse, an agent that will not edit, MCP, timeouts and quotas." +icon: "life-ring" --- -## Start here +Most CLI problems are one of five things: you are not signed in, the coding service is unreachable, a host is not connected, a permission or mode is narrower than you think, or a run hit a limit. This page is ordered by the message or symptom you actually see, so you can jump to the one in front of you. + +Start with the diagnostic block below whatever the symptom is. It takes ten seconds and it answers most of the follow-up questions before you have to ask them. + +## Start with six commands ```bash cortex --version cortex whoami -cortex debug paths # where config, sessions, logs, and caches are +cortex debug paths # where config, sessions, logs and caches are cortex debug config # the configuration actually in effect cortex debug system # platform and environment details cortex logs -n 200 # recent log output ``` -For a single run, `-v` and `--trace` increase console verbosity and can expose sensitive context. `--debug` instead records bounded, content-free diagnostics under the Cortex home `diagnostics/` directory (or `CORTEX_DIAGNOSTICS_DIR`); it never uploads anything. - -## “The coding service is temporarily unavailable” +`cortex debug config` is the one people forget. It shows the configuration in effect after your profile, your project file and any `-c` overrides have been merged, which is usually where a surprising behaviour comes from. `cortex debug config --diff` narrows it to where your project file and your profile disagree, and `cortex debug config --env` adds the Cortex environment variables that are influencing the result. -<Frame caption="The outage state: the error, what to do next, and a composer that retries on Enter — your work so far is saved in this session."> - <img src="/images/cli/runtime/120x40/error-unavailable.png" alt="Cortex CLI showing The coding service is temporarily unavailable with a retry composer" /> -</Frame> +<Note> +`-v` and `--trace` raise console verbosity for a single run, and that output can include the contents of your prompts and files. `--debug` is the safer switch: it records bounded, content-free diagnostics under the Cortex home `diagnostics/` directory, or the directory named by `CORTEX_DIAGNOSTICS_DIR`. Each entry carries eight fields and nothing else: `schema`, `timestamp`, `version`, `operation`, `trace_id`, `span_id`, `status` and `duration_ms`. There is no prompt text, no file content, no path and no account identifier, because the recording API takes no user-supplied string at all. A journal file stops at 2 MiB, the directory keeps at most 64 of them, entries older than 7 days are pruned, and on Unix-like systems the files are written owner-read-write only. It never overwrites `./debug.txt`, and it never uploads anything. +</Note> -Cortex could not reach the coding API. The message is deliberately the whole story — the CLI does not surface provider, SDK, or transport names. +## The service, the host, and signing in -1. Can this machine reach `api.cortex.foundation`? -2. Is a proxy in the way? Corporate TLS interception can break calls even when browsing works. -3. Is `CORTEX_API_URL` set to something unexpected? `cortex debug config --env` tells you. -4. Are you signed in? `cortex whoami`. +### The coding service is temporarily unavailable -Press **Enter** to retry; the session is saved. +This means the CLI could not reach the coding service. The message is deliberately the whole story: the CLI does not name a provider, an SDK or a transport, so there is nothing further hidden behind it. Four checks, in order: -## “This PC and SSH Code execution require an already connected Code session” +1. Can you reach `api.cortex.foundation` from this machine? +2. Is a proxy in the way? `HTTPS_PROXY` and `HTTP_PROXY` are honoured for `cortex scrape`, but corporate TLS interception can still break other calls. +3. Is `CORTEX_API_URL` set to something unexpected? `cortex debug config --env` will tell you. +4. Are you signed in? Run `cortex whoami`. -You selected This PC or SSH — through `CORTEX_COMPUTER` or `CORTEX_SSH_HOST` — without a connected Code session. Those hosts are never created on the fly, and the Cloud is not substituted. Either resume a session that already has the host, or unset `CORTEX_COMPUTER` to use the Cloud. See [Code on desktop](/code/desktop). +If all four look right, check [status.cortex.foundation](https://status.cortex.foundation) before digging further. -## The TUI will not start +### This PC and SSH Code execution require an already connected Code session -Cortex needs a terminal on both stdin and stdout. In a pipeline, a CI job, or under a wrapper that redirects either, it refuses and points you at [`cortex run` or `cortex exec`](/cli/headless). +You selected This PC or SSH, with `CORTEX_COMPUTER` or `CORTEX_SSH_HOST`, without a connected Cortex Code session. Those hosts are never created on the fly, and Cloud is not quietly substituted, because running your tools somewhere other than where you asked is worse than refusing. Either resume a session that already has a host, or unset `CORTEX_COMPUTER` to use Cloud. See [Cloud, This PC, and SSH](/cli/hosts). -## Sign-in problems +### Sign-in does not complete -See [Sign in → Troubleshooting](/cli/sign-in#troubleshooting). - -## The agent will not change anything +Device and single sign-on flows, expired credentials, and headless machines with no browser are covered on [Sign in](/cli/sign-in). `cortex login status` reports where you stand, and `cortex whoami` shows the account a run will use. -Check, in order: +### The interface will not start -1. **Mode.** Plan and Ask are read-only. **Shift+Tab** to **Agent**. -2. **Sandbox.** `--sandbox read-only` blocks all writes; `workspace-write` confines them to the workspace. -3. **Approval policy.** With `--ask-for-approval never` and no autonomy the agent may be declining rather than prompting. -4. **The `permission` table** in `config.toml` can deny `edit` or specific command patterns outright. -5. **Agent tool access.** An agent with `tools: read-only` cannot write, whatever the session policy says. -6. **Spec mode.** Mutating tools stay locked until the plan is accepted. +The CLI needs a terminal on both standard input and standard output. In a pipeline, a CI job, or under a wrapper that redirects either one, it refuses to start and points you at `cortex run` or `cortex exec`. That is the fix, not a workaround: see [Headless and scripting](/cli/headless) and [CI and automation](/cli/ci). -`cortex debug config --diff` shows what differs from the defaults. +## The agent will not change anything -## A tool is not available +Work down this list in order. One of the six is almost always the answer, and `cortex debug config --diff` shows what differs from the defaults. + +<Steps> +<Step title="Check the mode"> +**Plan** mode is read-only by design. Press `Shift+Tab` to cycle to **Agent**. See [Plan and Spec modes](/cli/plan-mode). +</Step> +<Step title="Check the sandbox"> +`--sandbox read-only` blocks all writes. `workspace-write` confines them to the workspace instead of forbidding them. +</Step> +<Step title="Check the approval policy"> +With `--ask-for-approval never` and no autonomy granted, the agent may be silently declining rather than prompting you. +</Step> +<Step title="Check the permission table"> +The `[permission]` table in `config.toml` can deny editing, or specific shell command patterns, outright. A project file can carry it too, and a project file beats your own. See [Permission policy](/cli/policy). +</Step> +<Step title="Check the agent"> +An agent defined with read-only tools cannot write, whatever the session policy says. `cortex agent show <name>` prints its definition. +</Step> +<Step title="Check for Spec mode"> +In Spec mode the mutating tools stay locked until the submitted plan is accepted. +</Step> +</Steps> + +### A tool is not available ```bash cortex exec --list-tools ``` -Something narrowed the set: `--enabled-tools` / `--disabled-tools`, the agent's `tools` field, the current mode, or the `permission` table. - -## An edit broke the build - -After an edit, a **Diagnostics** row lists compiler errors and warnings with file and line, so the agent — and you — can see what to fix next. `/diagnostics [file]` runs the same check on demand. - -<Frame caption="An Edit row followed by Diagnostics: one error and one warning, each with its location."> - <img src="/images/cli/runtime/120x40/diagnostics.png" alt="Cortex CLI Diagnostics row listing an error and a warning after an edit" /> -</Frame> +If a tool you expect is missing, something narrowed the set: the agent's own tool list, the current mode, or the `[permission]` table. `--enabled-tools` and `--disabled-tools` are not the cause, because `cortex exec` accepts them only alongside `--list-tools`. [Tools the agent uses](/cli/tools) lists the full set and what each one needs. ## An MCP server is not connecting ```bash -cortex mcp list --all -cortex mcp debug <name> +cortex mcp list --all # is it there, and is it enabled? +cortex mcp debug <name> # try the connection cortex mcp debug <name> --test-auth --no-cache ``` -Common causes: the stdio command is not on `PATH` in the environment Cortex launches it from; a missing `--` in `cortex mcp add` made the server's flags Cortex flags; the URL points at localhost or a private range and needs `--allow-local`; the bearer-token environment variable named in the config is not set. In the TUI, a failed server shows a red `×` in `/mcp` with **r** to reconnect. +Four causes account for most failures: -## Quota exhausted +- The local command is not on `PATH` in the environment the CLI launches it from. +- A `--` was missing from `cortex mcp add`, so the server's own flags were parsed as CLI flags. +- The URL points at localhost or a private range and needs `--allow-local`. +- The bearer token environment variable named in the configuration is not set in the environment the CLI is running in. -<Frame caption="× Agent quota exhausted: the meter, the reset time, and the two ways to continue now. The composer holds follow-ups until the window resets."> - <img src="/images/cli/runtime/120x40/quota-exhausted.png" alt="Cortex CLI quota exhausted state with a held composer" /> -</Frame> +[MCP servers](/cli/mcp) has the full add-and-authorise flow. -The composer is held — *Add a follow-up — held until quota resets* — and follow-ups queue until the window resets. `/usage` shows the details. Quotas fail closed; see [Plans and quotas](/getting-started/plans). +## Runs, limits and output -## A run times out +### A run times out -`cortex exec` defaults to a 600-second timeout and 100 turns. +`cortex exec` defaults to a 600-second timeout and 100 turns. Raise both for a genuinely large task: ```bash cortex exec --timeout 1800 --max-turns 40 "large task" ``` -If one shell command is the problem, raise `--command-timeout` or `execution.command_timeout_seconds` instead. Splitting a large task into several runs usually beats raising the ceiling. +If a single shell command is the problem rather than the whole run, raise `--command-timeout` or `execution.command_timeout_seconds` instead. Breaking a large task into several smaller runs is usually better than raising the ceiling: each run starts with a clean context and you get to check the work in between. + +### Quota exhausted -## Output is truncated or mangled +When the quota for your plan runs out, the run stops and the composer is held: `Add a follow-up — held until quota resets`. Follow-ups you type queue until the window resets rather than being lost. `/usage` shows the detail. See [Plans and quotas](/getting-started/plans). -`--color never` (or `NO_COLOR`) for logs and pipelines. `-o json` or `-o stream-json` when something downstream parses the output; the shape of `text` is not a contract. +### Output is truncated or mangled -## Disk usage keeps growing +- Use `--color never` for logs and pipelines, or set `NO_COLOR` in the environment. +- Use `-o json` or `-o stream-json` when something downstream parses the output. The shape of `text` output is not a contract, and it can change between releases; the JSON envelope is the stable surface. + +### Disk usage keeps growing ```bash cortex compact status @@ -115,21 +131,41 @@ cortex cache clear cortex logs --clear --keep-days 7 ``` -Lock the sessions you want to keep first: `cortex lock add <SESSION_ID> -r "keep for the audit"`. +Lock the sessions you want to keep before you run a cleanup, so it skips them: + +```bash +cortex lock add <SESSION_ID> -r "keep for the audit" +``` + +[Data locations](/cli/data-locations) explains what lives where, and which directories are safe to delete by hand. -## A build from source fails +### A build from source fails -On Linux the optional audio and desktop crates need ALSA headers: `sudo apt-get install -y libasound2-dev pkg-config`. Use the toolchain pinned in `rust-toolchain.toml`. +On Linux, the optional audio and desktop components need ALSA headers, so install them and use the toolchain the repository pins: -## Reporting a problem +```bash +sudo apt-get install -y libasound2-dev pkg-config +``` + +The prebuilt binaries on [software.cortex.foundation](https://software.cortex.foundation) are the supported path for everyday use. See [Install the CLI](/cli/install). + +## Report a problem ```bash cortex feedback bug "describe what happened" --include-logs ``` -Or `/bug` in the TUI, or open an issue at [github.com/CortexLM/cli](https://github.com/CortexLM/cli). +`--include-logs` attaches recent local log output to the report, so read it first if the run involved anything you would not want to share. Submissions queue in the Cortex home `feedback/` directory when you are offline and go out on the next successful call. `cortex feedback history` shows what you have sent. + +<Tip> +Include three lines from the diagnostic block in any report: the `cortex --version` output, whether `cortex whoami` resolves, and the platform line from `cortex debug system`. That trio answers the first round of questions on its own. +</Tip> ## Related -- [Configuration](/cli/configuration) · [Sign in](/cli/sign-in) · [Modes and permissions](/cli/modes-and-permissions) -- [Troubleshooting the web app](/getting-started/troubleshooting) +- [Install the CLI](/cli/install) +- [Sign in](/cli/sign-in) +- [Modes and permissions](/cli/modes-and-permissions) +- [Cloud, This PC, and SSH](/cli/hosts) +- [Headless and scripting](/cli/headless) +- [Command reference](/cli/reference) diff --git a/cli/tui.mdx b/cli/tui.mdx index 3b62ac4..fe3e325 100644 --- a/cli/tui.mdx +++ b/cli/tui.mdx @@ -1,130 +1,178 @@ --- title: "The TUI" -description: "What is on screen when you run cortex — the timeline and its rows, the composer, the status line, queueing follow-ups, and the panels behind Ctrl+K." -keywords: ["interface", "screen", "layout", "panels"] +description: "What is on screen when you run cortex: the timeline, the composer and its chips, the footer hints, the panels, and the alternate screen" +icon: "window-maximize" --- -`cortex` with a terminal attached starts the interactive UI. It takes the full viewport by default (the alternate screen) and gives you three things: a **timeline** of the conversation and the agent's work, a **composer** at the bottom, and a **footer** with the model, the mode, and the most useful shortcut. +Run `cortex` in a terminal and you get the interactive app: a **timeline** of the conversation and the agent's work, a **composer** at the bottom with a mode chip on its top border and a model chip on its bottom border, and a **footer** strip of the shortcuts that apply right now. It takes the whole viewport by default and gives your scrollback back when you leave. -<Frame caption="The empty composer: > with a block caret, the placeholder “Plan, search, build anything”, the mode on the top border, the model chip Cortex Mini 1 (medium) on the bottom border, and the footer hints."> - <img src="/images/cli/runtime/120x40/composer-empty.png" alt="Cortex CLI empty Agent composer with the model chip on its border" /> -</Frame> +This page covers how to start it, what each region of the screen shows, the timeline rows and tool tiles, the composer and its sigils, queueing a follow-up while a turn runs, the panels and overlays, and how to interrupt or quit. The controls that decide what the agent is allowed to do are on [Modes and permissions](/cli/modes-and-permissions). -## Starting it +## Start it ```bash -cortex # current directory -cortex "review the auth module" # start with a prompt already submitted -cortex --cd /path/to/project # another working root -cortex --model <model-id> # pick a model for this session -cortex --profile work # load a profile from config.toml -cortex --no-alternate-screen # stay inline in the host terminal +cortex # the current directory +cortex "review the login module" # start with a prompt already submitted +cortex --cwd /path/to/project # use another directory as the working root +cortex --model <model-id> # pick a model for this session +cortex --profile work # load a named profile from config.toml +cortex --no-alternate-screen # stay inline in the host terminal ``` -The TUI needs a terminal on both stdin and stdout; if either is redirected it refuses to start and points you at [`cortex run` or `cortex exec`](/cli/headless). +The TUI needs a real terminal on both standard input and standard output. If either is redirected it refuses to start and points you at [`cortex run` or `cortex exec`](/cli/headless) instead. -## The welcome splash +## The first screen -Before the first turn the timeline shows two lines — *Welcome to Cortex, the coding agent CLI* and `v0.1.x · / commands · @ files · ! shell · & cloud` — plus a first-run tips panel. After your first turn the splash is dropped; an empty session is composer and footer only. +Before your first turn the timeline shows a two-line welcome: -## Timeline rows +``` +Welcome to Cortex, the coding agent CLI +v<version> · / commands · @ files · ! shell · & cloud +``` -| Row | Looks like | Meaning | -| --- | --- | --- | -| Your prompt | `> add ioredis and a mock for the tests` on a light bar, with the time | A message you submitted | -| Thinking | `♦ Thought for 1.4s` | The model reasoned before acting | -| Agent prose | Rendered markdown — headings, lists, tables as an ASCII grid, code between hairlines with a language tag and line numbers | The model's reply, streamed | -| Tool call | `● Shell $ cargo test -p cortex-tui · ✓ 0 · 41s` | A tool the agent invoked, with a short summary and result | -| Edit | A unified diff: dim gutter, red `-`, green `+`, a `+N -N` stat | A file change | -| Worked for | `Worked for 4.6s` | The turn finished | -| Stopped | `× Stopped` | You interrupted the turn | -| Subagent task | `● Task <type>` with a todo list beneath | Work delegated to a subagent | +On a first run a tips panel appears with it. It points you at switching model and reasoning effort, adding `@` files for context, pressing `Shift+Tab` to cycle Agent / Plan / Ask, and opening Settings with `F2`. A narrow terminal gets a shorter variant of the same welcome. + +After your first turn the welcome is dropped: an empty session is composer and footer only. The TUI deliberately never paints a fake shell prompt, an echoed command, a working directory or a logo. + +## The screen, region by region -Tool rows collapse to a summary; with the timeline focused, press **e** to expand or collapse the selected one. +| Region | What it holds | +| --- | --- | +| Header, left | Nothing. It is empty by design, so no path is echoed there | +| Header, right | The token counter, drawn as a pair such as `0 / 500K` | +| Timeline | Your prompts, the agent's prose, tool tiles, thinking rows, diagnostics and errors | +| Status line | While a turn runs: a spinner, the stage it is in, and the elapsed time | +| Composer | Two hairlines, the mode chip on the top border, the model chip on the bottom border, the `>` sigil at the start of your input | +| Footer | The shortcut hints for the current context | -<Frame caption="Tool tiles: a grouped “3 tool calls” header, Read and Grep rows with their summaries, and a Shell row whose failing test is quoted beneath it."> - <img src="/images/cli/runtime/120x40/tool-tiles.png" alt="Cortex CLI timeline with Read, Grep, and Shell tool rows and a failing test result" /> -</Frame> +The stage on the status line reads *Thinking*, *Executing* with the tool name, *Streaming* or *Delegation*. -<Frame caption="An Edit tile: the unified diff with a dim gutter, red removals, green additions, and a +2 −1 stat."> - <img src="/images/cli/runtime/120x40/diff-hunk.png" alt="Cortex CLI edit tile showing a unified diff hunk" /> -</Frame> +<Note> +The token counter is a pair of numbers, not a promise. The real context window depends on the model you are using, and the counter can read zero until the first turn finishes. Treat the figure on screen as informational. +</Note> -## The status line +## Timeline rows and tool tiles -While a turn runs, a line above the composer shows a spinner, the stage — *Thinking*, *Executing <tool>*, *Streaming*, *Delegation* — the elapsed time, tokens used, and **esc to interrupt**. +| Row | On screen | Meaning | +| --- | --- | --- | +| Your prompt | Your text on a light bar | A message you submitted | +| Thinking | `♦ Thought for 1.4s` | The model reasoned before acting | +| Agent prose | Rendered markdown, with code between hairlines | The reply, streamed as it arrives | +| Read | `● Read src/cortex-tui/src/composer.rs · 212 lines` | A file the agent read | +| Grep | `● Grep "alternate_screen" in src/ · 6 hits in 4 files` | A content search | +| Edit | `● Edit … · +12 −3` with a `▸ show diff` affordance | A file change, expandable to the diff | +| Shell | `● Shell $ cargo test -p cortex-tui` with the exit status and how long it took | A command the agent ran | +| Running | `⠇ Shell … · running · 8s` | A tool still in flight | +| Grouped calls | `▾ 3 tool calls Read ×2 · Grep ×1` | Several calls folded into one row | +| Diagnostics | `● Diagnostics src/…/composer.rs · 2`, then one line per problem | Results from the language server | +| Subagent | `● Task <type>` with a todo list beneath it | Work delegated to a subagent | +| Turn end | `Worked for 12s · 4.1k tokens` | The turn finished | +| Interrupted | `× Stopped` | You interrupted the turn | +| Cloud hand-off | `↑ Handed off to Cortex Cloud` | The task went to [Cortex Cloud](/cli/hosts) | + +Tool rows collapse to a summary. With the timeline focused, press `e` to expand or collapse the selected one. The exact wording of the elapsed-time and token rows is still settling, so do not script against it. ## The composer -- `> ` with a block caret; the dim placeholder *Plan, search, build anything* until you type. -- **Enter** sends. **Shift+Enter** (or **Alt+Enter**) inserts a newline. **Up** / **Down** walk your prompt history. -- Type `/` for [slash commands](/cli/slash-commands); type `@` to reference a file or symbol; both autocomplete in a popup. A line starting with `/` that is not a known command is sent to the agent as an ordinary message. -- `!` runs a shell command directly. `&` prefixes a task to hand off to Cortex Cloud — the timeline shows *Handed off to Cortex Cloud* with the agent and branch, and `/jobs` follows it. -- Submit while a turn is running and the message is **queued** — the composer reads *Add a follow-up — Enter to queue* and shows how many are waiting. +- `Enter` sends. `Alt+Enter` inserts a newline. `↑` and `↓` walk your prompt history, and `↑` on an empty composer edits your last message. +- The mode chip sits on the top border and the model chip on the bottom border, drawn as the model's name with its reasoning effort in brackets, for example `Cortex Mini 1 (medium)`. +- A [goal](/cli/goal), if the session has one, adds a chip immediately after the mode chip. + +Four characters at the start of a line open something instead of being sent as text: + +| Sigil | Opens | +| --- | --- | +| `/` | The slash-command list. A line starting with `/` that is not a known command is sent to the agent as ordinary text | +| `@` | The file picker, to add a file or symbol to the context | +| `!` | Bash mode, where what you type runs in your shell. The sigil changes from `>` to `!` | +| `&` | A hand-off of the task to Cortex Cloud | + +The placeholder tells you what the composer will do with what you type: + +| State | Placeholder | +| --- | --- | +| Default | `Plan, search, build anything` | +| A turn is running | `Add a follow-up — Enter to queue` | +| A prompt is waiting for you | `Choose an option above` | +| Just after you stopped a turn | `Reply, or ↑ to edit your last message` | +| Ask mode | `Ask about the codebase — read-only` | +| Plan mode | `Describe what you want — Cortex drafts a plan first` | +| Your quota is used up | `Add a follow-up — held until quota resets` | -<Frame caption="Typing: the placeholder is gone, the caret follows the text, and the footer switches to Enter:send · Alt+Enter:newline."> - <img src="/images/cli/runtime/120x40/composer-typing.png" alt="Cortex CLI composer with a prompt being typed" /> -</Frame> +## Queue a follow-up while a turn runs -<Frame caption="Two follow-ups queued behind a running Shell command — sent when the current step finishes. ↑ edits a queued item."> - <img src="/images/cli/runtime/120x40/queue.png" alt="Cortex CLI with a running Shell tool and two queued follow-ups" /> -</Frame> +You do not have to wait for a turn to end. Type while it runs and `Enter` **queues** the message instead of sending it; the composer shows how many are waiting, and `↑` edits a queued message. The queue is sent in order as the turn frees up. -<Frame caption="A hand-off: & fix the flaky login redirect test and open a PR — the timeline shows the Cloud agent id, its branch, and where to follow it."> - <img src="/images/cli/runtime/120x40/cloud-handoff.png" alt="Cortex CLI showing Handed off to Cortex Cloud with agent, branch, and follow links" /> -</Frame> +`Esc` interrupts the turn instead. The timeline records `× Stopped`, and the composer invites you to reply or edit your last message. -## Footer +## Footer hints -Left: the model, the mode, and remaining context — `Cortex Mini 1 · Agent · 92% context`. Right: one shortcut hint — `shift+tab to cycle modes`, or the palette's own keys while it is open. A token counter (`14K / 500K`) sits top right. +The footer strip changes with what is on screen. Two examples, exactly as they are drawn: -## Modes and autonomy +``` + Shift+Tab:mode | Ctrl+x:shortcuts + Enter:send | Alt+Enter:newline | Shift+Tab:mode | Ctrl+x:shortcuts +``` -**Shift+Tab** cycles **Agent → Plan → Ask**. `/mode` opens the same picker; `/permissions` sets **Read-only**, **Smart**, or **Full access**; `/plan` drafts a plan before writing any code. Approvals appear inline as numbered choices. Everything about these controls is on [Modes and permissions](/cli/modes-and-permissions). +Every context gets its own strip: idle, text typed, a narrow terminal, a turn running, the queue, the model and effort lists, an approval prompt, the MCP and plugins panels, the resume picker, Bash mode, the command palette, the undo sheet, a rate limit, a feature that is unavailable, and more besides. The strip shows the keys that apply at that moment; it is not the complete list of bindings. For that, use the shortcuts sheet, or see [CLI keyboard shortcuts](/cli/keyboard). -## Panels +## Panels and overlays -Most of the surface area is one key or one slash command away: +Most of the surface area is one slash command away. | Panel | Open with | | --- | --- | -| Command palette | **Ctrl+K** or **Ctrl+P**, or `/palette` | -| Sessions | **Ctrl+S** or **Ctrl+O**, or `/sessions` | -| Model picker | **Ctrl+M**, or `/model` | -| MCP servers | **Ctrl+E**, or `/mcp` | -| Transcript | **Ctrl+T**, or `/transcript` | -| Shortcuts overlay | **Ctrl+X** | -| Settings | **F2**, or `/settings` | -| Help | **?** or **F1**, or `/help` | -| Theme picker | `/theme` | -| Background tasks | `/jobs` or `/tasks` | -| Rewind overlay | **Esc** twice quickly | +| Settings | `F2`, or `/settings` | +| Shortcuts sheet | `/shortcuts` (alias `keys`) | +| Model list, and the effort list behind `Tab` | `/models` | +| MCP servers | `/mcp` | +| Plugins | `/plugins` | +| Sessions | `/sessions` | +| Resume picker | `/resume` | +| Rewind overlay | `Esc` twice in quick succession | +| Command palette | `/palette`, or `Ctrl+p` | +| Background tasks | `/tasks` | +| Transcript | `/transcript` | +| Search past sessions | `Ctrl+r` | + +Panels title themselves with a count, in the pattern `MCP servers · 2 of 4 connected`. A list longer than the panel ends with `… 87 more — keep typing to filter`, so filtering is always the way through a long list. Approval prompts are not a panel: they appear inline in the timeline and the composer waits for you. See [Modes and permissions](/cli/modes-and-permissions). -## Interrupting and quitting +Settings opens on categories, with `/ to search` inside it. `↑`/`↓` or `j`/`k` navigate, `g` and `G` jump to top and bottom, `Space` or `Enter` toggles a row, `→` expands a submenu, `d` resets a row, and `F2` or `Esc` closes. Appearance holds the display rows: `Compact mode`, `Default screen mode`, `Show timestamps`, `Show thinking blocks`, `Group tool calls`, `Collapsed edit blocks`, `Line numbers`, `Word wrap`, `Syntax highlight`, `Animations` and `Theme`. Themes are on [Themes](/cli/themes). -- **Esc** interrupts the current turn. The timeline records `× Stopped`; the CLI aborts its stream and tells the runtime to cancel. -- **Esc** twice quickly opens the rewind overlay to step back or fork. See [Sessions](/cli/sessions). -- **Ctrl+Q** or `/quit` quits. **Ctrl+C** force-quits. +## Alternate screen and small terminals + +The TUI enters the **alternate screen** by default, which is why your shell scrollback is intact when you exit. Three ways to change that: + +```bash +cortex --no-alternate-screen # inline, this run +cortex --alternate-screen # full screen, this run +``` + +```toml +[tui] +alternate_screen = true +``` -<Frame caption="After Esc: the Shell row is marked stopped, the timeline records × Stopped with the time and tokens spent, and the composer offers ↑ to edit your last message."> - <img src="/images/cli/runtime/120x40/interrupt-stopped.png" alt="Cortex CLI after interrupting a turn — × Stopped" /> -</Frame> +The Appearance row `Default screen mode` is the same setting in the UI, drawn as `Fullscreen` or `Inline`. -## When the service is unreachable +The chrome holds its shape when the window is small: at roughly 40 columns by 12 rows the composer keeps its border, its chips and one footer hint, and the welcome copy switches to its narrow variant. Below that the layout has nothing left to fold. -The TUI says **The coding service is temporarily unavailable** and offers to retry — *your work so far is saved in this session*. That is the whole message by design: Cortex does not surface provider, SDK, or transport names. See [Troubleshooting](/cli/troubleshooting). +A `▼` marker appears in the timeline when there is more content below. -## Display +## Usage and quota -`/theme` switches between **Cortex Night** (default), **Cortex Day**, **Ocean Dark**, and **Monokai**. `/compact` toggles a denser layout. The accent is Cortex green `#1F4945` on the focused control; the rest of the chrome is grey. See [Extend → Themes](/cli/extend#themes). +A usage row names your plan and when it renews, in the pattern `Usage · Cortex Pro · renews Oct 1`. When the agent allowance is used up the row becomes `× Agent quota exhausted` and the composer holds new messages until it resets. Per-plan numbers are not published in the CLI itself; check your account for those. -The chrome holds its shape in a small terminal. At 40 columns by 12 rows the composer keeps its border, mode label, model chip, and footer hint: +## Interrupt, quit, and failures -<Frame caption="The empty composer at 40×12 — the same chrome, folded to a small window."> - <img src="/images/cli/runtime/40x12/composer-empty.png" alt="Cortex CLI empty composer rendered in a 40 by 12 terminal" /> -</Frame> +- `Esc` interrupts the running turn. `Esc` twice in quick succession opens the rewind overlay, which steps back through the session or forks it. See [CLI sessions](/cli/sessions). +- `Ctrl+Q` or `/quit` quits. `Ctrl+C` force-quits. +- If the coding service cannot be reached, the timeline says `× The coding service is temporarily unavailable` and invites you to try again in a moment. That is the whole message on purpose: the CLI does not surface provider, library or transport names. Your work so far stays in the session. See [CLI troubleshooting](/cli/troubleshooting). ## Related -- [Slash commands](/cli/slash-commands) · [Keyboard shortcuts](/cli/keyboard) -- [Sessions](/cli/sessions) — what happens after you close the terminal. +- [Modes and permissions](/cli/modes-and-permissions) - what the mode chip and the approval prompt control +- [Slash commands](/cli/slash-commands) - everything behind `/` +- [CLI keyboard shortcuts](/cli/keyboard) - bindings by context +- [CLI sessions](/cli/sessions) - resume, rewind and fork +- [Headless and one-shot runs](/cli/headless) - when there is no terminal to draw to diff --git a/code/approvals.mdx b/code/approvals.mdx new file mode 100644 index 0000000..a771d69 --- /dev/null +++ b/code/approvals.mdx @@ -0,0 +1,95 @@ +--- +title: "Permissions and approvals" +description: "Commands ask with Allow once, Always allow and Deny. File writes never use that rail: they wait in Changes for a human Approve." +icon: "hand" +--- + +Cortex Code stops and asks before it does something consequential. There are **two separate gates**, and they use different words on purpose: a command that needs a decision raises a card above the transcript with **Allow once**, **Always allow** and **Deny**, while a file write never appears on that card at all and instead waits in the **Changes** pane for a human **Approve**. + +Keeping those two apart is the whole point of this page. A session-level **Always allow** on a command never grants a file write, and no approval in Code can be undone after the fact. This page covers both gates, the two narrower consents on top of them (an exact prepared action, and metered spend), who is allowed to decide, and what deliberately does not exist. + +## Two gates, side by side + +| | Gate 1: a command | Gate 2: a file write | +| --- | --- | --- | +| What it covers | A tool call that needs a decision, including running a shell command | Writing or editing a file in the repository | +| Where it appears | A card above the transcript | The **Changes** tab in the output pane | +| The words | **Allow once**, **Always allow**, **Deny** | **Approve**, **Approve all**, **Reject** | +| How far a yes reaches | **Always allow** covers that tool for the rest of this session | An approval covers that one write and nothing later | +| If you say no | The turn continues and the model is told it was denied | The file is not written, and your note goes back to the agent | + +## Gate 1: a command that needs a decision + +When a tool call needs your decision, the turn stops and a card appears above the transcript. It carries the tool's name in a warning badge, a one-line summary of what is being asked, and the detail in a monospaced block so you can read the exact command before you answer. + +| Button | What it does | +| --- | --- | +| **Allow once** | Lets that one call proceed. The next similar call asks again. | +| **Always allow** | Stops asking for that tool **in this session**. It is a session grant, not an account setting: it does not carry to another session, to Cortex Chat, or to the Cortex CLI. | +| **Deny** | Refuses the call. The turn keeps going and the model is told the call was denied. A denial is not a crash. | + +If a decision cannot be recorded, a toast reads **That decision could not be recorded**. Press the button again. + +<Note> +Treat the three buttons as what the screen offers when a command is put to you, not as a guarantee that every tool in every deployment will stop and ask. The gate you can rely on is the file-write gate below: a write always waits for a human. +</Note> + +## Gate 2: a file write waits in Changes + +Writes and edits are deliberately excluded from the card above the transcript. They land in the **Changes** pane as pending files, and **until a human approves one, the tree is not written**. + +<Steps> + <Step title="Open the Changes tab"> + Each file the agent touched is listed with its state: **Queued**, **Writing**, **Pending**, then **Written**. + </Step> + <Step title="Read the proposed diff"> + A pending file is a proposal. Read it before you answer, not after. + </Step> + <Step title="Approve or reject"> + Press **Approve** on a file, or **Approve all** for the batch. Press **Reject** to refuse one, and where the surface offers it, say why under **Why reject this write** so the agent reads your reason and can try something else. + </Step> +</Steps> + +Approving grants exactly the write in front of you. In the product's own words: **Always applies this write once. It does not grant every later edit.** There is no grant anywhere in Code that hands the agent standing permission to write files, and an **Always allow** you pressed on a command has no effect here. + +In **Ask** or **Plan** the pane reads **Ask and Plan do not change files, so there is nothing to review here.** If the gate itself cannot be read, it says **Pending file writes could not be loaded.** rather than showing an empty list. The full pane, including the difference between a proposed and a landed diff, is documented in [Changes and diffs](/code/changes). + +## Exact-action consent + +Sometimes an agent finishes a turn with an action already prepared, a push for example. Those appear under the heading **Actions**, with the hint **Bound to this turn · no model**. Pressing one opens a dialog titled **Run this action?** whose body reads **No model turn. The payload was bound when the agent stopped. Cloud guest only.**, with **Allow** and **Deny**. + +The distinction matters. **Allow** runs exactly the payload that was frozen when the agent stopped, with no further model turn, so nothing can be reinterpreted between your decision and the action. **Deny** starts nothing at all. The dialog states the accounting plainly: **The press is audited. This action expires with its turn.** + +An action carries one of five states: `pending`, `running`, `completed`, `expired` and `denied`. An expired action stays visible rather than disappearing, so you can see what was offered and never taken. + +## Spend consent + +Metered spend is a third, narrower gate with its own title, **Spend consent**, and its own hint: **Allow this metered spend once, allow up to a budget, or deny it. A decision cannot be changed.** It offers **Allow once**, **Allow up to** with an **Amount** field, and **Deny**. A failure reads **That spend decision could not be recorded**. + +As a session approaches the budget you set, a banner reads **Approaching this session's budget**, followed by the amount used against the limit. Recorded cost for the workspace lives on [Usage](/code/usage). + +## Who is allowed to decide + +- **A viewer who has detached cannot decide.** The header's **Detach** control says so: **You are watching this session. Detach does not stop the turn. Attach again to send or to Allow or Deny.** Detaching never stops a turn; press **Attach** to get the buttons back. +- **Focus does not hide a decision.** Approvals still interrupt while the session is in **Focus**. +- **A guest cannot approve.** Two-person approval exists as a surface, with **People** and a line naming who the session is waiting on, and it states **A guest cannot vote.** How a second reviewer is nominated is not documented yet. +- **The side panel decides nothing.** **Ask on the side** is a scratch pad: **This panel does not run tools, settle approvals, or write Always-allow.** + +## What does not exist + +<Warning> +**There is no undo, no checkpoint and no revert anywhere in Cortex Code.** Nothing rolls a turn's edits back after they are approved. The moment to refuse a change is while it is still pending in **Changes**, with **Reject**, and the moment to refuse a command is while its card is on screen, with **Deny**. +</Warning> + +- **There is no command allowlist and no per-directory allowlist.** Running shell commands is allowed or withheld wholesale: **Agent** has it, **Ask** and **Plan** do not. There is no list of safe commands or safe folders to maintain. +- **There is no workspace-level shell policy.** [Code settings](/code/settings) says it in its own words: a shell-command policy, a network allowlist, a branch prefix and pull-request behaviour are decided per session today, and a session asks before it runs a command so you can allow, always-allow or deny it. +- **Withholding beats approving.** If you do not want a turn to edit or run anything at all, do not rely on denying each prompt: send the turn in **Ask** or **Plan**, where those tools are absent from the catalog the turn is built with. See [Ask, Plan, Agent](/code/interactions). + +## Related + +- [Changes and diffs](/code/changes) for the write gate in full, per file and per batch. +- [Ask, Plan, Agent](/code/interactions) for withholding a tool instead of refusing it every time. +- [Code sessions](/code/sessions) for attach, detach, stop and follow-ups. +- [Modes and permissions in the CLI](/cli/modes-and-permissions) for the same decisions in a terminal. +- [Security and privacy](/reference/security-and-privacy) for what leaves your repository. +- [Code troubleshooting](/code/troubleshooting) when a decision will not record. diff --git a/code/automations.mdx b/code/automations.mdx new file mode 100644 index 0000000..b230328 --- /dev/null +++ b/code/automations.mdx @@ -0,0 +1,93 @@ +--- +title: "Automations" +description: "Automations are saved instructions for Cortex Code: a trigger, a repository and a prompt. Nothing runs unattended yet, and the page says so." +icon: "bolt" +--- + +An automation in Cortex Code is a saved instruction: a trigger, a repository and a prompt, kept so you do not rewrite the same task every week. The **Automations** page lists the ones you have saved, counts how their runs went, and offers a grid of ready-made ones to start from. + +Read the page's own description before you plan anything around it: **Saved instructions only. Schedules and events do not execute yet. Prepare a session, then send an interactive turn to start work.** That sentence is the whole truth of the feature today, and the rest of this page is written around it. + +<Warning> +**Nothing runs unattended.** A saved cron schedule does not fire, and neither does a pull request opening or a push. Cortex Code is not wired to your code host as an app that can wake a session: a person presses a control and then sends a turn. If you need work that genuinely runs on a schedule, that is a Cortex Bot feature; see [Routines](/bot/routines). +</Warning> + +## What an automation is made of + +Three parts, saved together: + +- A **trigger**, which records when you would want this to happen. +- A **repository**, which is what the prepared session will point at. +- A **prompt**, which is the task itself, written the way you would write it for a colleague. + +The triggers that render are **cron** with a schedule, **on PR opened**, **on PR push**, **on push** and **manual**. Saving any of them records your intent and nothing more: none of them starts a session today. + +## Create one + +<Steps> + <Step title="Open Automations"> + Press **New automation**, or pick a row from **TEMPLATES** to start from a written prompt instead of a blank one. + </Step> + <Step title="Give it a trigger, a repository and a prompt"> + Choose the trigger that describes your intent, the repository the work belongs to, and write the prompt. Treat the trigger as a label for now, not as a switch. + </Step> + <Step title="Save it, then enable it"> + The row toggle is what enabling means here, and the hint is exact: **Allows preparing a session manually. This does not enable unattended execution.** + </Step> + <Step title="Prepare a session"> + The run control on the row is **Prepare session**, and it is disabled until the automation is enabled. Pressing it creates a queued session from the automation. + </Step> + <Step title="Send a turn"> + Open that session and send a turn. Nothing runs until you do. From there it is an ordinary Code session: the same modes, the same transcript, the same two gates. + </Step> +</Steps> + +If preparing fails, the page says **The run could not open a session**, or falls back to **That did not work**. Nothing is half-started when it does. + +## What the page shows you + +| Element | What it reads | +| --- | --- | +| Stat | **AUTOMATIONS** with the total, noting how many are enabled | +| Stat | **SUCCEEDED · 7D**, either `No runs yet` or a percentage of runs | +| Stat | **FAILED · 7D**, either `Nothing pending` or a count still pending, highlighted once anything is | +| Sections | **YOUR AUTOMATIONS**, then **TEMPLATES** | +| Row status | **Never run**, or the run's own status word in a badge | +| Empty page | **No automations yet**, the same saved-instructions description, and **Create one** | + +The two run cards count the last **seven days**. That window is the only number on the page. The second grid is called **TEMPLATES** rather than anything that implies a recommendation, because nothing computes a suggestion for you: they are the same six rows for everybody. + +Each automation also has its own view with its runs listed, which is where you look after preparing one. What Cortex tells you about a run, and about the session it produced, lands in the inbox: Cortex says when a session finishes, when it needs a decision, and when an automation ran. See [Code notifications](/code/notifications). + +## The six templates + +| Template | Trigger it saves | What its prompt asks for | +| --- | --- | --- | +| **PR review recipe** | on PR opened | review the diff, report blocking and major findings with file and line, and say plainly when it found nothing | +| **Dependency maintenance** | a nightly cron | update dependencies to their latest compatible versions, run the test suite, and open a pull request only if everything passes | +| **Security scan** | on push | audit the dependency tree and the changed files for known vulnerabilities, prioritising injection, authorisation bypass and leaked secrets | +| **Test coverage** | a weekly cron | find the least-covered modules and write tests that assert real behaviour rather than implementation details, then open a pull request | +| **Release notes draft** | a weekly cron | summarise the pull requests merged this week, grouped by user-visible change, fix and internal work | +| **Issue triage** | manual | take the newest untriaged issue, try to reproduce it, and either open a fix or comment with what it found | + +Picking a template opens the create form with its prompt already written, and you can rewrite that prompt before you save. A template is a starting point, not a contract. + +<Note> +The **PR review recipe** template is not the same thing as Cortex Security. Security is a review that reads a pull request and posts checks on it, with its own install; an automation is a saved prompt for a Code session that writes code. See [Pull-request review](/code/security). +</Note> + +## Why the honest framing matters + +It would be convenient to describe a saved cron schedule as a job that fires. It is worth saying why we do not. + +A Code session has no undo, no checkpoint and no revert. There is also no command allowlist and no per-directory allowlist to pre-authorise what a run may touch, so everything a turn is permitted to do is decided before it starts: the mode it runs in, the repository and branch it is pointed at, and the fact that a person is there to answer a command prompt and to approve or reject each file write. A run nobody is watching would have none of that, and nothing to roll back afterwards. + +So the useful way to think about an automation today is as a saved brief with a known blast radius: the prompt is written once and reviewed once, and a person still opens the gate each time. See [Permissions and approvals](/code/approvals) and [Changes and diffs](/code/changes). + +## Related + +- [Code notifications](/code/notifications) for what Cortex tells you after a run. +- [Routines](/bot/routines) for work that really does run on a schedule. +- [Code sessions](/code/sessions) for the session a prepared automation becomes. +- [Permissions and approvals](/code/approvals) for the gates a prepared run still passes. +- [Pull-request review](/code/security) for reviews that read a pull request. diff --git a/code/changes.mdx b/code/changes.mdx new file mode 100644 index 0000000..3e2bfcc --- /dev/null +++ b/code/changes.mdx @@ -0,0 +1,98 @@ +--- +title: "Changes and diffs" +description: "The Changes pane is where a file write waits for a human Approve, and where a proposed diff becomes a landed one." +icon: "code-compare" +--- + +When an Agent turn touches a file, the file does not quietly change. It appears in the **Changes** tab of the session's output pane with a state you can read, and it waits there for a human decision. This is the gate that matters most in Cortex Code: a write is never covered by a session-level permission, and the tree is not written until someone presses **Approve**. + +This page covers the **Changes** tab and its per-file controls, the difference between the diff you read before a write and the diff you read after it, the live **Diff** tab, commenting on a line, and where the branch and the pull request show up. The command side of permissions lives on [Permissions and approvals](/code/approvals). + +## The Changes tab + +The output pane on the right of a session carries the tabs **Changes**, **Diff**, **Git**, **Terminal** and, when there is one, **Plan**. **Changes** opens on the files this turn has touched, with a header count that reads **1 file changed** or **3 files changed** as the turn goes on. While the pane is reading the runtime it says **Loading changes…** + +Each file carries one of four states: + +| State | What it means | +| --- | --- | +| **Queued** | The agent intends to write this file; nothing has happened to it yet. | +| **Writing** | The write is in flight inside the runtime. | +| **Pending** | The write is proposed and waiting for your decision. This is the one that needs you. | +| **Written** | The write has been applied in the runtime's working tree. | + +Controls in the pane: + +- **Approve** on a single file, labelled **Approve this file** for screen readers, and **Reject**, labelled **Reject this file**. +- **Approve all** and **Reject** for the whole batch. +- **Follow**, which becomes **Following**, pins the pane to whichever file is being written so you do not have to chase a long turn. + +If the working tree cannot be read the pane says **The changes could not be read from the runtime.** rather than showing you an empty diff, and if the write gate itself cannot be read it says **Pending file writes could not be loaded.** Either way, nothing has been approved on your behalf. + +## Approve or reject a write + +<Steps> + <Step title="Open Changes and read the pending file"> + A **Pending** file is a proposal. Read the diff in front of you before you answer. + </Step> + <Step title="Approve what you have read"> + Press **Approve** on the file, or **Approve all** when you have read the batch and want it applied together. + </Step> + <Step title="Reject what you do not want, and say why"> + Press **Reject** to refuse the write. Where the surface offers the note, write your reason under **Why reject this write**: the agent reads it and can propose something else on the next turn. + </Step> +</Steps> + +The diff you approve is the one that was sealed when the agent proposed it, not a fresh read taken while you were deciding. A preview that cannot be read cannot be approved, and the destination path is confirmed again immediately before the write lands. + +<Warning> +**There is no undo, no checkpoint and no revert.** **Reject** is only available while a write is **Pending**. Once a write is **Written** there is no control anywhere in Code that takes it back, so read a diff before you approve it rather than after. +</Warning> + +## A proposed diff and a landed diff are not the same + +The same pane shows you two different things at two different moments, and it is worth knowing which one you are looking at. + +| | Proposed diff | Landed diff | +| --- | --- | --- | +| When | Before the write is approved | After the branch exists | +| What it is | What the agent intends to do to the file | What is actually in the session's branch | +| What you can do | **Approve** or **Reject** it | Read it, comment on it, open a pull request | + +A **Pending** row with a diff is a proposal about the future. A **Written** row is history. If you find yourself wanting to change your mind, check which of the two you are reading: only the first can still be refused. + +## The Diff tab reads the runtime live + +The **Diff** tab is not a stored snapshot. It reads the working tree of the runtime the session attached, right now, which is why its caption reads **Live from the Cloud guest**. If the tree cannot be read, the tab reports **The changes could not be read from the runtime.** + +Every Cloud session works in its own isolated worktree, shown on the worktree strip as **Isolated · Cloud guest** with the hint **Each Cloud session uses its own isolated worktree. Chat and the CLI are not this page.** **New worktree** starts a fresh one, and reads **Opening…** while it does. See [Repositories and branches](/code/repositories). + +## Comment on a line + +Any line of a diff can start an inline comment. The box reads **Write a follow-up about this line…**, with **Cancel** and **Send as follow-up**. + +<Note> +An inline comment is sent as a normal follow-up turn, not stored as a code annotation. It is the fastest way to say "this line is wrong, and here is why" without retyping the file name, but it starts a turn like any other follow-up. +</Note> + +## From a change to a pull request + +The **Git** tab carries the branch and the pull request. It reads **No branch yet** until a Cortex branch has been created, then either **No pull request** or **Open pull request** once there is one. Cortex pushes only to its own branches, so an agent cannot push over your default branch. + +That is the shape of the whole product: changes arrive as a branch and a pull request, never as a patch to copy out of a box. + +## In Ask and Plan there is nothing here + +In **Ask** or **Plan** mode the pane says so instead of looking broken: + +> **Ask and Plan do not change files, so there is nothing to review here.** + +Those two modes are built without the write and edit tools at all, so no pending file can exist. See [Ask, Plan, Agent](/code/interactions). + +## Related + +- [Permissions and approvals](/code/approvals) for the command gate, and why it never covers a write. +- [Ask, Plan, Agent](/code/interactions) for withholding the write tools for a whole turn. +- [Code sessions](/code/sessions) for the transcript beside this pane. +- [Repositories and branches](/code/repositories) for the worktree and the base branch. +- [Code troubleshooting](/code/troubleshooting) when a diff will not load from the runtime. diff --git a/code/cli.mdx b/code/cli.mdx index daf9636..9fd36d7 100644 --- a/code/cli.mdx +++ b/code/cli.mdx @@ -1,73 +1,92 @@ --- title: "Code in the terminal" -description: "The Cortex CLI drives the same Code sessions from a terminal — interactive, one-shot, or headless in CI. Same account, Cloud by default." -keywords: ["terminal", "command line"] +description: "The Cortex CLI drives the same Code sessions from a shell: what carries across, how the words map, and which CLI pages answer the rest." +icon: "terminal" --- -The Cortex CLI is Cortex Code for the terminal. One binary, `cortex`, gives you an interactive session view, one-shot runs from your shell, and a headless mode for scripts and CI. It talks to the same Code sessions as the web and desktop apps and signs in with the same account. The full documentation lives in the [CLI tab](/cli); this page is the map from Code concepts to CLI commands. +The Cortex CLI is Cortex Code in a terminal. It signs in with the same Cortex account and drives the same sessions, so a run you start from a shell is the same piece of work you can open in your browser: it appears on the sessions board marked **· Started from CLI**, with its transcript, its worklog and its approvals exactly where they would be if you had typed the task into the composer. The terminal is another front end onto Code, not a second product with its own history. -## Code concepts, CLI names +This page is the bridge between the two. It covers when the terminal is the better surface, how CLI vocabulary maps onto the words used throughout the Code tab, what does not carry across, and which pages of the [Cortex CLI](/cli/index) tab answer everything else. Installers, commands, flags and exit codes live there on purpose. A command list copied onto a Code page drifts out of date, so this page links instead of repeating. -| In Code | In the CLI | -| --- | --- | -| A session on a repository | `cd` into the project and run `cortex`; the CLI reuses the workspace's Code session id so turns continue the same session | -| Ask / Plan / Agent | `/mode`, or **Shift+Tab** to cycle Agent → Plan → Ask. `/plan` drafts a plan before writing code. | -| Stop | **Esc** — the timeline shows `× Stopped` | -| Cloud host | The default for the TUI and `cortex exec` | -| This PC / SSH | `CORTEX_COMPUTER=this_pc` or `CORTEX_COMPUTER=ssh`, with an already connected session | -| Approvals | Numbered prompts before consequential commands; `/permissions` sets Read-only, Smart, or Full access | -| Model | `/model` — Cortex Mini 1, Cortex 1, Cortex Max 1, with Low / Medium / High effort | -| Timeline | Tool rows — `● Shell`, `● Read`, `● Grep` — with results indented beneath | - -## Install and first session - -<CodeGroup> -```bash macOS and Linux -curl -fsSL https://software.cortex.foundation/install.sh | sh -``` - -```powershell Windows -irm https://software.cortex.foundation/install.ps1 | iex -``` -</CodeGroup> - -```bash -cortex login -cd ~/code/my-project -cortex -``` - -Type what you want changed and press **Enter**: +## When to reach for the terminal -```text -> add a /healthz endpoint and cover it with a test -``` +The terminal is the right surface when the work starts where you already are. You are in a project directory, you want to describe a change without leaving the shell, and you want the result as a branch and a pull request like any other Code session. It is also the only way to drive Code from a script or a pipeline, which the CLI has a dedicated headless mode for. -<Frame caption="A prompt typed into the CLI composer. The footer switches to Enter:send · Alt+Enter:newline while you type."> - <img src="/images/cli/runtime/40x12/composer-typing.png" alt="Cortex CLI composer with a prompt being typed, rendered in a 40 by 12 terminal" /> -</Frame> +Stay in the browser when the work is about reading rather than typing. The **Changes** pane, the live diff of the attached runtime, the **Plan** tab and the pull-request link are browser surfaces, and a pending file write is answered there with **Approve** whichever surface started the session. Approvals belong to the session, not to the window you happen to have open: attach to the session in the browser and you can answer them there. -Details: [Install](/cli/install), [Sign in](/cli/sign-in), [CLI quickstart](/cli/quickstart). +## Code words, CLI words -## One-shot and headless +The concepts are the same on both sides. Only the names differ, and this is the map. -```bash -cortex run "explain the release process" -cortex exec --auto read-only --git-diff "review my uncommitted changes" -``` - -`cortex run` streams a formatted answer into your shell and understands sessions. `cortex exec` is for CI: autonomy levels, JSON output, turn and time limits. See [Headless runs](/cli/headless). - -## What the CLI is — and is not - -| The CLI does | The CLI does not | +| In Code | In the CLI | | --- | --- | -| Drive Code sessions from a terminal | Run the model on your laptop | -| Work in a project directory | Replace Cortex Chat | -| Offer This PC and SSH | Put those hosts in the browser | -| Extend with MCP servers, skills, agents, hooks, plugins | Manage Bot or Design | - -## Next - -- [CLI overview](/cli) — the full tab. -- [Code on desktop](/code/desktop) — the same hosts in the desktop app. +| a session | a run | +| the interaction mode, **Ask**, **Plan** or **Agent** | the auto level | +| the runtime a turn binds to | the executor, or the computer | +| the **Changes** pane | `--git-diff` | + +When you are describing something to a colleague looking at the browser, use the Code words. When you are reading CLI help output, expect the CLI words. + +## Where a run executes + +The CLI makes the same runtime choice Code makes everywhere else, and it makes it the same way: **Cloud** is the default, and **This PC** and **SSH** are opt-in. Both of those need an already connected Code session. The CLI will not create one for you on the fly, and it will not quietly substitute Cloud without saying so, because a turn binds one runtime and there is no silent fallback. + +The switches that select a host from your shell are the CLI's own, and they are documented with it in [environment variables](/cli/environment-variables) and [Cloud, This PC, and SSH](/cli/hosts). If a run refuses This PC or SSH, clearing that override returns you to Cloud, which is the usual fix. + +<Warning> +Treat local and SSH execution as unfinished. The choice and the screens exist, but Cortex does not promise a complete run of the tools on This PC or on an SSH host today. When you need a run you can rely on end to end, use Cloud. See [Cloud runtimes](/code/runtimes). +</Warning> + +## What the terminal does not change + +- **The two gates stay separate.** A command that needs a decision is answered with **Allow once**, **Always allow** and **Deny**; a file write is never on that rail and waits in **Changes** for a human **Approve**. What the prompt looks like in a shell is on [Modes and permissions](/cli/modes-and-permissions); what the gates mean is on [Permissions and approvals](/code/approvals). +- **There is still no undo, no checkpoint and no revert.** Refusing a write while it is pending is the moment that matters, in a terminal exactly as in a browser. +- **A mode is a lock on the next turn.** Switching between Ask, Plan and Agent changes the tools the turn is built with, so the change applies to the turn after it, never to the one already running. See [Ask, Plan, Agent](/code/interactions). +- **Extension points belong to the CLI.** The CLI has its own tool servers, skills, agents, hooks and plugins, all documented in its tab. Those are the CLI's, not a Code session's: a Code session in the browser is given no tool servers, no connectors and no plugins of its own, and can say so under its **Tools** tab. + +<Note> +Do not assume the two surfaces are feature-for-feature identical. Cortex does not specify parity between Cloud and the terminal, and the tool names differ between them. Before you plan around something, check the CLI page that owns it. +</Note> + +## One control that is browser-only + +The command palette has an **Initialise the repository** row, reached by opening the palette and typing `init` or `/init`. It writes an `AGENTS.md` file inside a Cloud guest, and its dialog explains the choice plainly: **Writes AGENTS.md in this Cloud guest. Keep leaves an existing file. Replace overwrites it.** If no session is attached it says **Open a Cloud session first.**, and where the deployment does not offer it, **Initialise is not available on this deployment.** + +That row is a control in the browser, not a CLI command. Do not go looking for it in help output. + +## What the CLI tab documents + +<CardGroup cols={2}> + <Card title="Cortex CLI" icon="terminal" href="/cli/index"> + The map of the whole tab: the three ways to run it, and what the CLI does and does not do. + </Card> + <Card title="Install the CLI" icon="download" href="/cli/install"> + Getting the binary on macOS, Linux and Windows, pinning a version, and upgrading. + </Card> + <Card title="Sign in" icon="right-to-bracket" href="/cli/sign-in"> + Signing in with your Cortex account, including machines without a browser. + </Card> + <Card title="CLI quickstart" icon="rocket" href="/cli/quickstart"> + A first turn in a real project, and how much autonomy to grant on day one. + </Card> + <Card title="Cloud, This PC, and SSH" icon="server" href="/cli/hosts"> + Where a run actually executes, opting in to the other hosts, and why they fail closed. + </Card> + <Card title="Modes and permissions" icon="sliders" href="/cli/modes-and-permissions"> + The auto level, the approval prompt, and the permission rules the CLI reads. + </Card> + <Card title="Headless and one-shot runs" icon="gears" href="/cli/headless"> + Driving a run from a script or a pipeline, with machine-readable output. + </Card> + <Card title="CLI troubleshooting" icon="life-ring" href="/cli/troubleshooting"> + The diagnostics first, then the messages a terminal run can print. + </Card> +</CardGroup> + +## Related + +- [Cortex Code](/code/index) for what Code is and how a session is put together. +- [Code sessions](/code/sessions) for the board, attach and detach, stop and continue. +- [Code on desktop](/code/desktop) for the other surface that offers This PC and SSH. +- [Permissions and approvals](/code/approvals) for the two gates in full. +- [Code troubleshooting](/code/troubleshooting) when a run refuses a host. diff --git a/code/cloud.mdx b/code/cloud.mdx deleted file mode 100644 index 54fe8de..0000000 --- a/code/cloud.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: "Cloud runtimes" -description: "Every web Code session runs in its own isolated Cloud guest, prepared by the agent for that repository. Not the Chat Python sandbox, not the API process." -keywords: ["runtime", "guest", "sandbox", "environment"] ---- - -Web Code runs your repository in an **isolated Cloud guest** — a headless virtual machine on the same farm as Bot computers. The guest is started for the session, attached, and prepared by the agent. Workspace tools execute inside it and nowhere else. - -## How a guest starts - -<Steps> - <Step title="You name a repository on the session"> - From Code Home or the repository picker. - </Step> - <Step title="Cortex starts and attaches a guest"> - One repository per runtime. The guest is isolated from other sessions and other accounts. - </Step> - <Step title="The agent prepares the environment"> - It installs what the repository needs, based on what it finds — not a script guessed from a filename. - </Step> - <Step title="Tools run inside the guest"> - Reads, edits, shell commands, tests. Never in the API process, never in Chat's Python sandbox. - </Step> -</Steps> - -If the deployment has no Cloud compute available, Code says so. It does not run your repository on the API instead. - -## Three different machines - -| Surface | Machine | Desktop | Workspace | -| --- | --- | --- | --- | -| **Code Cloud** | Isolated Cloud guest | No — headless | Your repository | -| **Chat Python** | A small snippet sandbox | No | None — the snippet only | -| **Bot computer** | Isolated Cloud guest | **Yes** — screen, browser, shell | The bot's own files | - -Do not mix them up. Chat Python cannot see a Code repository; a Code guest cannot reach a Bot's desktop. See [Security](/security/overview). - -## Environment and secrets - -Environment for a guest belongs to that guest. Set what a session needs inside the session — the agent can create the files or export the variables the repository expects. **There is no Secrets page**; `/code/secrets` sends you home. For unattended runs, pass credentials through the environment of the machine running the CLI, never on the command line. See [Headless runs](/cli/headless). - -## Lifecycle - -| Event | What happens | -| --- | --- | -| Session starts | Guest starts, attaches, prepares | -| You stop a turn | The turn cancels; the guest and its files stay | -| The session idles | The guest may hibernate; the next turn wakes it before the model is prompted | -| You return later | The session resumes on its guest with the repository as you left it | - -## Hosts beyond the Cloud - -The Cloud is the only host in the browser. **This PC** and **SSH** exist on the desktop app and the CLI — see [Code on desktop](/code/desktop). Those hosts require an already connected Code session; Cortex never silently substitutes the Cloud for a host you chose. - -## When there is no capacity - -A guest is a real machine, so a session can fail to start for operational reasons rather than a bug in your repository. Both cases fail closed and name the reason: - -| Code | What happened | What to do | -| --- | --- | --- | -| [`no_capacity`](/problems/no_capacity) | No guest could be started right now | Try again shortly. Higher plans get priority when the fleet is busy | -| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Too many sessions or runs active on the account | Let one finish, then start this one | -| [`service_unavailable`](/problems/service_unavailable) | The service is temporarily unavailable | Retry after a pause — your session and its files stay as they were | - -Code never runs your repository on the API process as a fallback, and it never reports a started session that has no guest behind it. See [Troubleshooting](/code/troubleshooting) and the [problem catalog](/problems). - -## Related - -- [How Code works](/code/how-it-works) — the tool catalog that runs in the guest. -- [Sessions](/code/sessions) -- [Code troubleshooting](/code/troubleshooting) — Cloud availability and failed starts. -- [Bot computer](/bot/computer) — the guest that does have a desktop. diff --git a/code/desktop.mdx b/code/desktop.mdx index 32119a0..a6dce4a 100644 --- a/code/desktop.mdx +++ b/code/desktop.mdx @@ -1,55 +1,96 @@ --- title: "Code on desktop" -description: "This PC and SSH hosts for Code sessions exist on the desktop app and the CLI. The browser stays Cloud-only — host placement, not a missing feature." -keywords: ["This PC", "SSH", "local", "app"] +description: "What the Cortex desktop app adds to Code: This PC and SSH next to Cloud, its own screens, and the host status it reports." +icon: "desktop" --- -In the browser, a Code session runs in the Cloud. Install the [Cortex desktop app](/getting-started/desktop) or the [CLI](/cli) and two more hosts appear: **This PC**, which runs the workspace tools on your own machine, and **SSH**, which runs them over the shell of a host you register. +Cortex Code runs in your browser, in the Cortex desktop app and in the Cortex CLI. The desktop app is the surface that can put a session on a machine you own: next to **Cloud** it offers **This PC**, which is the app's label for your own computer, and **SSH**, which is a remote host you have registered. In the browser a session runs on Cloud, plus a registered team runner when the deployment has one, and nothing else. -## Where each host lives +Two things in Code are called Desktop, and this page is about one of them. The **Cortex desktop app** is the application you install and sign into. A session's **Desktop** tab is something else entirely: it carries the badge **Soon** and there is nothing behind it, because a Cloud guest is headless and there is no screen inside a Code runtime. Everything below is about the application. -| Host | Browser | Desktop app | CLI | Desktop for the agent | -| --- | --- | --- | --- | --- | -| **Cloud** | Yes | Yes | Yes (default) | No — headless guest | -| **This PC** | No | Yes | Yes, opt-in | Your machine | -| **SSH** | No | Yes | Yes, opt-in | Shell only | +## Where each runtime is offered -Web Code is Cloud-only by design: the browser has no way to run tools on your disk. That is host placement, not a missing catalog entry. +| Surface | Runtimes offered | +| --- | --- | +| Browser | **Cloud**, plus a registered team runner when the deployment has one | +| Desktop app | Cloud, **This PC**, **SSH** | +| Cortex CLI | Cloud by default; This PC and SSH by opt-in | -## This PC +Web Code is Cloud-only on purpose: the browser has no way to run tools on your disk. For the same reason, the browser's **Machines** page lists Cloud occupancy and team runners only, and never your desktop hosts. A session binds one runtime per turn and there is no quiet fallback: if the runtime you chose is not usable, the turn refuses and tells you what to do rather than running somewhere else. -The agent works in a project directory on your machine, using your toolchains, your network, and your hardware. Approvals and sandbox policy apply exactly as they do elsewhere — see [Modes and permissions](/cli/modes-and-permissions) for the CLI's controls. +## Screens in the desktop app -Good for: private dependencies, local databases, GPU work, anything the Cloud guest cannot reach. +The app is not a wrapper around this site. It has its own screens, and they are the same vocabulary you already know from the browser: -## SSH +- A first-launch splash, then Code **Home** with the composer. +- An **Inbox** of your sessions, and a session detail with its plan, its permission prompts, its terminal and its changes. +- **Automations**, **Review**, **Usage** and **Notifications**. +- **Settings**, which holds **Providers**, workspace defaults and a remote host, with **Integrations** under it. +- **Connect a server**, which is where a remote host is registered. -The agent runs shell tools on a host you register, over SSH. There is no desktop on that host; it is a shell. Good for: build boxes and servers you already operate. +Those are screens inside the application, not pages on this site. Downloading and updating the app is covered under [the desktop app](/getting-started/desktop). -## Choosing a host +## Run a session on This PC -**Desktop app:** pick the host when you start the session. +<Steps> + <Step title="Choose This PC on Code Home"> + The runtime row on the desktop app offers Cloud, **This PC** and **SSH**. Picking This PC means the tools a turn calls act on a folder you nominate. + </Step> + <Step title="Pick the folder in the native folder picker"> + The app opens your operating system's own folder picker. There is no workspace-name field to fill in, and pressing **Cancel** leaves no session behind and invents no path: nothing falls back to whatever directory the app happens to be running in. + </Step> + <Step title="Work from the folder's name"> + Afterwards the session identifies the folder by its name rather than its full path, and it uses that name exactly as it is, trailing spaces included. + </Step> +</Steps> -**CLI:** the TUI and `cortex exec` use the Cloud unless you opt in: +A This PC start never silently becomes a Cloud session. If the host behind a session goes away, the follow-up box is disabled and says so: **This session runs on This PC, and no host is connected. Pair one from the Host pane and the composer comes back.** -```bash -CORTEX_COMPUTER=this_pc cortex # run tools on this machine -CORTEX_COMPUTER=ssh cortex # run tools over SSH -CORTEX_SSH_HOST=build-box cortex # naming an SSH host also selects SSH -``` +**This PC is not a Cortex Bot host.** It is Code's own local runtime, and the SSH screens never borrow that name either: SSH stays SSH. -This PC and SSH need an **already connected Code session**. Cortex will not create one on the fly and will not substitute the Cloud silently; if you select a host without a connected session, the CLI tells you so in plain words. Either resume a session that already has the host, or unset `CORTEX_COMPUTER` to use the Cloud. See [CLI configuration](/cli/configuration). +## Run a session over SSH -<Frame caption="The CLI composer once a host is connected. Whichever host runs the tools, the session looks the same from here."> - <img src="/images/cli/runtime/40x12/composer-hover.png" alt="Cortex CLI composer with the pointer over it, rendered in a 40 by 12 terminal" /> -</Frame> +SSH runs the tools on a machine you already operate. There is no screen on that host, it is a shell, which makes it a good fit for a build box or a server with access your laptop does not have. Register one with **Connect a server** in the desktop app: keys stay server-side, and the browser never receives SSH keys or host keys. See [SSH hosts](/code/ssh-hosts) for the rest. -## Bot has the same shape +<Warning> +Treat local and SSH execution as unfinished. The desktop app offers the choice and the screens described here, but Cortex does not promise a complete run of the tools on This PC or on an SSH host today. When you need a run you can rely on end to end, use Cloud. See [Cloud runtimes](/code/runtimes). +</Warning> -Bot's Computer rail follows the same rule: **Cloud** in the browser, **This PC** on the Bot desktop app, **SSH** as shell only. See [Bot computer](/bot/computer). +## Approvals on a desktop session + +Nothing about the desktop app makes a turn quieter. A command that needs a decision stops the turn and asks, with **Allow**, **Always** and **Deny**, and file writes and shell commands are never silent. + +The two gates stay separate here exactly as they do in the browser. A command is decided on the prompt; a file write is not on that rail at all, it waits under **Changes** for a person to approve it, and a session-level always never covers a write. There is no undo, no checkpoint and no revert anywhere in Code, so a pending change is the moment to refuse. See [Permissions and approvals](/code/approvals) and [Changes and diffs](/code/changes). + +## Signed out, and where credentials live + +Signed out, desktop Code Home stays visible: This PC, SSH and Cloud are still shown, and so are **Ask**, **Plan** and **Agent**. Pressing start raises the sign-in dialog instead of failing. Automations, Review, Usage, Cloud and SSH also stay visible, and stay locked. + +Provider credentials are entered under **Settings → Providers**, and the form never reads a key back to you. Code has no Secrets destination on any surface, and nothing in Code asks you to paste a token. + +## The host status the app reports + +The app shows one status for the host behind your work, and it is worth knowing what each one means. + +| Status | What it tells you | The line it shows | +| --- | --- | --- | +| **Permission blocked** | a session is blocked on a decision | **A session is waiting on Allow, Always, or Deny.** | +| **Cloud session running** | work is alive in Cortex cloud | **A Cloud session is running.** | +| **Failed wake** | a remote host did not come back | **The remote Code host did not come back.** | +| **Connecting** | a host is being attached | **Connecting to the Code host…** | +| **Connected** | a host is attached and named | the machine itself, as **this Mac**, **this PC**, **this machine** or **this device**, or the name of the remote host you configured | +| **Cloud only** | no local host, so Cloud is the runtime | **The browser cannot run the local harness.** signed out, or **Cloud-only on the web, or connect a Cortex Code host.** signed in | + +The order is deliberate. A session waiting on Allow, Always or Deny is shown ahead of whether your own machine is up, then a running Cloud session, then a failed wake, then connecting, and only then connected or Cloud only. That is why a session running in Cortex cloud reads **Cloud session running** even while the local side is down: what matters is the work, not the laptop. + +## The same choice from the terminal + +The Cortex CLI drives the same sessions and makes the same runtime choice, on Cloud by default with This PC and SSH by opt-in. Both of those need an already connected Code session; the CLI will not create one on the fly and will not substitute Cloud without telling you. The switches themselves are documented with the CLI, in [environment variables](/cli/environment-variables), and the vocabulary map between Code words and CLI words is on [Code in the terminal](/code/cli). ## Related -- [Desktop app](/getting-started/desktop) — download and sign in. -- [Cloud runtimes](/code/cloud) — the default host. -- [Code in the terminal](/code/cli) +- [Cloud runtimes](/code/runtimes) for the default runtime and how a guest is prepared. +- [SSH hosts](/code/ssh-hosts) for registering and choosing a remote host. +- [Machines](/code/machines) for Cloud occupancy and team runners in the browser. +- [The desktop app](/getting-started/desktop) for downloading it and signing in. +- [Code in the terminal](/code/cli) for the same sessions from a shell. diff --git a/code/environments.mdx b/code/environments.mdx new file mode 100644 index 0000000..61ac91f --- /dev/null +++ b/code/environments.mdx @@ -0,0 +1,110 @@ +--- +title: "Environments and images" +description: "Start an environment for a repository, save it as an image so the next session skips the install, then launch, rebuild or delete it." +icon: "box" +--- + +**Environments** is the one page in Cortex Code that exists for this subject, and its own description is the clearest definition available: **An environment is a headless machine of its own: Cortex clones a repository into it and the harness installs what the repository declares. Saving one lets the next session skip the install.** + +That last sentence is the whole point. A plain Cloud session installs your toolchain every time it starts. An environment you have saved as an **image** is already installed, so the next session on the same repository and ref resumes from it instead of waiting. This page covers starting one, saving it, launching it again, rebuilding it, deleting it, and the three situations in which the feature is not available to you at all. + +## The three sections of the page + +| Section | What it holds | +| --- | --- | +| **START ONE** | The form that places a new environment: **Repository** and **Ref** | +| **MACHINES** | The environments running right now, each with a delete control | +| **SAVED IMAGES** | The snapshots you kept, each with **Launch**, **Rebuild** and delete | + +When nothing is running, **MACHINES** reads **No environments running** and explains where to start one and what it costs you: **Start one from a repository above, or from a session's Host tab. Each one occupies a host slot while it is placed.** The panel that copy calls the Host tab is the **Runtime** tab in an open session, described on [Cloud runtimes](/code/runtimes). + +## Start an environment + +<Steps> + <Step title="Fill in the repository"> + Under **START ONE**, put a repository in the **Repository** field. The hint tells you what it accepts: **A clone URL, or owner/name for GitHub.** + </Step> + <Step title="Choose a ref, or do not"> + **Ref** takes a branch or tag. **Empty uses the repository default.** + </Step> + <Step title="Watch it be placed"> + The new machine appears under **MACHINES** while it is placed. It occupies a host slot for as long as it is there, which is exactly why the page gives you a delete control. + </Step> + <Step title="Let the install finish"> + Cortex clones the repository and the harness installs what the repository declares. A session's **Runtime** tab shows the same work as **Install progress**. + </Step> +</Steps> + +You can also start an environment from inside a session, on its **Runtime** tab, without coming to this page at all. + +## Save an image + +An image is saved from a session's **Runtime** tab with **Save image**. The confirmation states the benefit precisely: **Environment saved** and **The next session on this repository and ref resumes from it.** + +An image is keyed by **repository and ref**. That pair is what a later session is matched against, so a saved image for one branch does nothing for a session started on a different one. Once saved, the snapshot appears under **SAVED IMAGES**. + +## Launch, rebuild, delete + +| Action | What it does | +| --- | --- | +| **Launch** | Starts an environment from the snapshot with no install. You do not retype the repository. The toast reads **Launching from the saved image** and **No install: the environment resumes from the snapshot.** | +| **Rebuild** | Deletes the image, then installs a fresh environment from scratch for the same repository and ref | +| Delete an image | Removes the snapshot. Its control is labelled **Delete the saved image for** the repository in question | +| Delete an environment | Frees the host slot the running machine occupies. Its control is labelled **Delete the environment for** the repository in question | + +Image actions are serialised, so two quick presses cannot race the same row. If you press twice, the second press waits rather than starting a second operation on the same image. + +### Rebuild is destructive, in that order + +**Rebuild** deletes the image first and then installs. The dialog says so before you commit, and it is worth reading in full: + +> **Rebuild this image?** +> +> **The saved image for** that repository and ref **is deleted, and a fresh environment starts for the same repository and ref. Nothing resumes from the old snapshot: the new environment installs what the repository declares, which takes as long as the first install did.** + +The buttons are **Cancel** and **Delete and rebuild**. After it runs, the toast repeats the consequence and tells you what to do next: **Rebuilding from scratch** and **The saved image is gone and a fresh environment is installing. Save it again from its Host tab once the install finishes.** Rebuild when the repository's dependencies have moved on and the snapshot has gone stale. Do not rebuild as a way to get the old snapshot back, because there is no way back. + +<Warning> +**There is no undo, no checkpoint and no revert anywhere in Code**, and that includes an environment. A deleted image is gone, a rebuild cannot be reversed, and a file write inside a running environment is either rejected while it is still pending or it lands. Review writes under **Changes** before they are applied rather than counting on rolling a machine back. See [Changes and diffs](/code/changes). +</Warning> + +## What can go wrong + +Every failure here is reported as a toast, and each one tells you whether anything changed: + +| Toast | What it means | +| --- | --- | +| **No environment capacity right now** | Nothing was placed. Try again later | +| **The environment could not be started** | The placement did not complete | +| **The image could not be launched** | The snapshot exists but did not start | +| **The image could not be rebuilt** | The rebuild did not complete | +| **The image was deleted, but no environment started** | The destructive half succeeded and the constructive half did not. Start one again from **START ONE** | +| **The environment could not be deleted** | The machine is still placed and still occupying its slot | + +If an environment is stopped and you bring it back, Cortex takes a capacity seat before it starts anything. When you are already at your ceiling it answers [`conflict`](/problems/conflict) instead of half-starting, and it refuses outright while the environment is still shutting down. Elsewhere a ceiling is reported as [`quota_exceeded`](/problems/quota_exceeded), nothing placeable as [`no_capacity`](/problems/no_capacity), and another attach racing yours as [`invalid_state`](/problems/invalid_state). + +## Ceilings + +Each account can hold **8** registered environments and **40** saved images. Deleting a machine you are no longer using frees a slot for the next one, and deleting an image you no longer launch frees one of the forty. No other number about an environment is worth planning around: whether one can be resized after it is placed, and how long a saved image is kept, are not documented, and an image is not something you can hand to a teammate today. + +## When environments are not available + +The page distinguishes three states, and only one of them is something you can act on: + +| What you see | What it means | Action | +| --- | --- | --- | +| **Sign in to use an isolated environment** and **An environment holds a clone of your repository and outlives the browser session that started it, so a guest could never come back to find or delete one.** | You are not signed in | **Sign in** | +| **Isolated environments are not enabled here** and **This deployment has no runtime fleet. Cloud sessions still run.** | The capability is not enabled on this deployment. This is not a plan prompt | none | +| **No environment capacity is available: the fleet is scaled to zero. Nothing was started, so nothing was lost.** | Capacity is momentarily at zero | **Try again** | + +<Note> +There is no offline or mock environment to develop against. Without a runtime fleet the feature cannot be tried at all, so the second row above is a genuine dead end rather than a slow path. +</Note> + +## Related + +- [Cloud runtimes](/code/runtimes) - what a session runs in, and the **Runtime** tab. +- [Repositories and branches](/code/repositories) - the repository and ref an image is keyed by. +- [Machines](/code/machines) - Cloud occupancy and team runners. +- [Changes and diffs](/code/changes) - the gate a write passes through inside an environment. +- [Code troubleshooting](/code/troubleshooting) - installs that do not finish. diff --git a/code/github.mdx b/code/github.mdx index bbbbfcb..89c4783 100644 --- a/code/github.mdx +++ b/code/github.mdx @@ -1,61 +1,89 @@ --- title: "Connect GitHub" -description: "Cortex Code reaches repositories through Connect GitHub — on Code Home, in the repository picker, and under Settings → Integrations." -keywords: ["repository", "repos", "connection", "Reconnect"] +description: "One control, one label, and no token to paste: how Cortex Code reaches your repositories, and what every failure message means." +icon: "github" --- -Code needs a repository to work on. You give it one by connecting GitHub from the product; Cortex then lists the repositories the grant covers and starts sessions on them. The same connection adds GitHub tools to Chat. +Cortex Code needs a repository to work on, and it gets one by connecting your GitHub account from inside the product. The connection is what lets Code list your repositories, prepare a session's runtime from one of them, and open a pull request when the work is done. Without it, the composer has nothing to point a session at. -<Frame caption="Settings → Integrations. Connect GitHub adds four GitHub tools to chat and unlocks repositories for Code."> - <img src="/images/product/settings-integrations.png" alt="Settings → Integrations — GitHub with a Connect GitHub button and tools listed; Linear, Slack, Notion, Vercel marked Soon" /> -</Frame> +There is exactly one control for this, it has one label per state, and **there is no token to paste, anywhere**. No personal access token field exists on any Cortex surface, and there is no fallback to one. This page covers the control, the four places it appears, what the connection is and is not, every message the connection can show you, and how to revoke it. + +## What the connection actually wires together + +Connecting GitHub gives Code three things: the list of repositories you can choose from, a clone in the runtime a session attaches, and the ability to push a Cortex-owned branch and open a pull request from it. Pushes stay on Cortex-owned branches, so the agent cannot push over your default branch. + +<Note> +It is not a connected app reaching into your session. A Code session is built with no tool servers, no connectors and no plugins of its own, and access you have granted in Chat or in Bot does not carry into Code: a session's own tools list can say as much. GitHub is not an exception dressed up as a connector; it is the repository source and the destination for a pull request. See [Code integrations](/code/integrations). +</Note> + +## The control, state by state + +| State | What you see | What it means | +| --- | --- | --- | +| Not connected | **Connect GitHub**, with the note **Connect GitHub to list your repositories and open pull requests.** | press it to start | +| Expired | **Reconnect GitHub** | the connection lapsed; it asks to be reconnected, not connected | +| Connected | no control and no note | there is nothing to do | +| Not available on this deployment | no control at all | the control is absent, not greyed out, because this deployment has no GitHub app to connect to | + +The same control, with the same label, appears in every place Cortex might reasonably ask you for it: the Code **Integrations** page, **Settings → Integrations**, the repository picker in the composer, and the getting-started row **Connect your GitHub account**. Whichever one you press, it is the same connection. + +A guest who presses it goes to sign-in, not to GitHub. Holding a connection requires an account, so the invitation comes first. ## Connect <Steps> - <Step title="Sign in"> - A guest cannot hold a GitHub grant — there would be no way to come back and revoke it. + <Step title="Sign in with your Cortex account"> + Then open Code. A guest can browse and type, but cannot hold a connection. </Step> - <Step title="Choose Connect GitHub"> - From **Code Home**, the **repository picker**, or **Settings → Integrations**. + <Step title="Press Connect GitHub"> + From the Code **Integrations** page, from **Settings → Integrations**, or straight from the repository picker in the composer, which offers the control instead of an empty list when there is nothing to list. </Step> - <Step title="Approve on GitHub"> - Grant access to the repositories you want Code to see. There is no personal-access-token field anywhere in Cortex; the connection is the only route. + <Step title="Authorise Cortex on GitHub"> + GitHub shows you its own consent screen and you decide there which repositories Cortex may see. Nothing in Cortex asks you for a credential, before or after. + </Step> + <Step title="Land back in Cortex"> + You return to a page that reads **Connecting GitHub** and **Finishing the connection…**, with **Cortex is finishing the connection with GitHub. This takes a moment.** It then reads **GitHub is connected. Taking you back…** (or `GitHub is connected as {label}. Taking you back…`, with the account it connected) and returns you where you started. </Step> <Step title="Pick a repository"> - Back in Code, choose a repository and start a session. See [Sessions](/code/sessions). + Back in the composer, the first chip is **Choose a repository** and the second is **Branch**. See [Repositories and branches](/code/repositories). </Step> </Steps> -## What the connection gives you - -| Surface | What GitHub adds | -| --- | --- | -| **Code** | The repository list; sessions clone and work inside the guest | -| **Chat** | Four GitHub tools — list pull requests, list issues, create an issue, and more — available in your conversations | -| **CLI** | `cortex pr <number>` to check out a pull request, and `cortex github install` to scaffold review workflows. See [Headless runs](/cli/headless) | +## If the connection does not finish -## If something is missing +Every one of these messages ends the same way: **Nothing was changed.** Connecting is all or nothing, so a failure leaves you exactly where you were and you can simply try again. -| What you see | What it means | Do this | +| Message | What happened | What to do | | --- | --- | --- | -| No **Connect** control | GitHub is not available on this deployment | Nothing to configure — the surface is not offered here | -| **Reconnect** | The grant lapsed or was revoked on GitHub | Choose **Reconnect** and approve again | -| The public `/code` page instead of Code Home | You are not signed in | Sign in | -| A repository is not listed | The grant does not cover it | Reconnect and include it, or adjust the installation on GitHub | +| **GitHub was not connected** + **Nothing was changed. Cortex Code needs a connected GitHub account to list your repositories and open pull requests.** | you pressed **Cancel** on GitHub's consent screen | nothing is wrong; this is a decision, not an error. Press **Connect GitHub** again when you want to | +| **The connection did not finish** + **Cortex could not finish the connection with GitHub. Nothing was changed.** | the round trip broke off | start again from **Connect GitHub** | +| **GitHub did not complete the connection** + **Try connecting again. Nothing was changed.** | GitHub answered with a failure | try again | +| **GitHub took too long** + **The connection was abandoned rather than left hanging. Try connecting again.** | GitHub did not answer in time | try again | +| **GitHub is not available to connect** + **GitHub isn't available to connect right now.** | GitHub is unreachable for now | wait and try again | +| **This connection attempt is no longer valid** + **Start again from Connect GitHub. Nothing was changed.** | the attempt went stale or was already used | begin a fresh attempt rather than reloading the old one | + +You may also see the flat label **GitHub could not be connected**. The callback page carries **Back to Code**, and on a failure it offers a fresh **Connect GitHub** that returns you to the Code integrations page. + +Cortex does not publish how long a connection lasts. You find out the ordinary way: the control reads **Reconnect GitHub**, which you press, approving on GitHub once more. + +## Disconnecting + +Revoke the connection from GitHub's own settings. Cortex has no disconnect button of its own that we can point you at, and revoking on GitHub always works: afterwards Cortex reports the connection as needing reconnection, or as not connected, and the repository list goes quiet until you connect again. ## Three different GitHub installs -| Install | Purpose | Where | -| --- | --- | --- | -| **Connect GitHub** | Repositories for Code sessions; GitHub tools in Chat | Code Home, repository picker, Settings → Integrations | -| **Cortex Security GitHub App** | Pull-request review as a check run | `/code/security` in the app — see [Cortex Security](/code/security) | -| **`cortex github install`** | Workflow files for CI review from the CLI | Your repository — see [Headless runs](/cli/headless) | +This is the most common confusion in the area, so it is worth stating plainly. Three separate things install against GitHub, and having one does not give you another. -Connect GitHub is not part of Chat's connector catalogue under **Customize**, and Code Cloud is not a plugin surface. +| Install | What it is for | Where it is documented | +| --- | --- | --- | +| **Connect GitHub** | lets Code list your repositories and open pull requests | this page | +| The **Cortex Security GitHub App** | lets Cortex Security read pull requests and post checks | [Pull-request review](/code/security) and [Cortex Security](/security/index) | +| The Cortex CLI's own install command | wires the CLI to GitHub | [Cortex CLI](/cli) | ## Related -- [Code quickstart](/code/quickstart) -- [Tools and connectors](/chat/tools) — the rest of Chat's connections. -- [Troubleshooting](/code/troubleshooting) +- [Repositories and branches](/code/repositories) for choosing what a session works on. +- [Code integrations](/code/integrations) for connected apps, repositories and tool servers. +- [Code quickstart](/code/quickstart) for a first session end to end. +- [Pull-request review](/code/security) for the separate Security install. +- [Code troubleshooting](/code/troubleshooting) when a repository you expect is not listed. diff --git a/code/how-it-works.mdx b/code/how-it-works.mdx index 8c97c0c..9f06ed2 100644 --- a/code/how-it-works.mdx +++ b/code/how-it-works.mdx @@ -1,70 +1,103 @@ --- title: "How Code works" -description: "Workspace tools execute inside the attached guest — never in the API process or Chat sandbox. Modes withhold mutating tools; compaction fails closed." -keywords: ["tool loop", "context", "compaction"] +description: "Cause and effect in a Code turn: where tools run, how a mode locks the toolset, the two approval gates, compaction, and how a turn ends." +icon: "diagram-project" --- -A Code turn is a tool loop like Chat's, with two differences that define the product: the tools operate on a real repository inside an isolated guest, and the mode you choose decides which tools the model is offered at all. +A Cortex Code turn is a loop. You describe a task, the agent calls tools, each result comes back, and it decides again until it has nothing left to call. Two things about that loop define the product: every tool runs inside the runtime the session attached, and the mode you chose decides which tools the turn was even built with. -## The workspace catalog +This page explains what happens between pressing **Start session** and reading a diff, so that the product's behaviour stops being surprising: why a mode change does not rescue a running turn, why a command asks permission in one place and a file write waits in another, and why a cancelled session says **Stopped** rather than **Failed**. -| Tool | What it does | -| --- | --- | -| `read_file` | Read a file from the repository | -| `write_file` | Create or replace a file | -| `edit_file` | Make a targeted edit | -| `glob` | Find files by pattern | -| `grep` | Search file contents | -| `bash` | Run a shell command in the guest — builds, tests, git | -| `todo_read`, `todo_write` | Keep a task list for the turn | -| plan tool | Write a plan — with a mermaid diagram — in Plan mode | +## Where a turn runs -All of these run **inside the attached guest**. `python` is a Chat tool; a Code turn runs the guest's own Python through `bash`. +A session binds one runtime, once per turn. There is no fallback. If the runtime you chose cannot be used, the turn refuses and tells you what to do rather than quietly running somewhere else. -## Attach before the first command +| Where it runs | What it is | What tools touch | +| --- | --- | --- | +| **Cloud** | an isolated guest on Cortex Cloud, prepared from your repository | the clone inside that guest | +| **This PC** | a machine you paired with the Cortex desktop app | the folder you picked | +| **SSH** | a registered remote host | that machine | +| nothing bound | no usable runtime | every call refuses, and says what to do | -If the session names a repository and no runtime is attached, the harness starts one, attaches it, and prepares the environment before the first tool runs. An unattached runtime is never the first thing a turn does. See [Cloud runtimes](/code/cloud). +Everything the agent does happens inside that runtime. Reads, searches, edits and shell commands all execute there. **Nothing runs in your browser**, and the browser never receives SSH keys or host keys. The browser offers Cloud, plus a registered team runner when the deployment has one; This PC and SSH belong to the desktop app and the CLI. See [Cloud runtimes](/code/runtimes) and [Code on desktop](/code/desktop). -## Modes decide the tools +## The turn loop, step by step -| Mode | Tools offered | -| --- | --- | -| **Ask** | Read-only: `read_file`, `glob`, `grep` | -| **Plan** | Read-only plus the plan tool | -| **Agent** | The full catalog, including `write_file`, `edit_file`, `bash` | +<Steps> + <Step title="You describe the task"> + You write the ask and press **Start session**. Cortex creates the session and opens it. On a follow-up, the same thing happens without the navigation. + </Step> + <Step title="The runtime attaches"> + The first turn attaches the runtime. A Cloud session gets its own isolated guest prepared from the repository you chose, which is why a first session on a repository spends time installing before any work shows up. + </Step> + <Step title="The agent works in rounds"> + Each round the agent may call tools: read a file, list files by pattern, search by regular expression, edit a file, run a command. Each call appears in the transcript as a **Read**, **Edited**, **Ran** or **Worked** row with a duration, and long finished output is shortened so the column stays readable. + </Step> + <Step title="Something needs your decision"> + A command that needs a decision stops the turn and raises a card above the transcript: **Allow once**, **Always allow**, **Deny**. A file write does not use that card at all: it appears in **Changes** waiting for a human **Approve**. + </Step> + <Step title="The turn ends"> + A turn ends when the agent stops calling tools, when you press **Stop**, or when it reaches the round budget for a Code turn. A Code turn gets many more rounds than a chat turn, because a real coding task legitimately takes a lot of them. + </Step> + <Step title="What is left behind"> + The session row and its title, the transcript, the plan if there is one, the worktree branch, the pull-request link and the recorded usage all survive the turn. + </Step> +</Steps> -Ask and Plan withhold the mutating tools in the harness. The model cannot edit or run anything in those modes because it is never offered the tools. See [Ask, Plan, Agent](/code/interactions). +## A mode is a lock on the toolset -## Stopping +**Ask**, **Plan** and **Agent** are not instructions to the agent to behave differently. They decide which tools exist in the catalogue the turn is built with. -A turn ends when the model stops calling tools or you press **Stop** (Esc in the CLI). Code does not copy Chat's eight-round budget; a coding task legitimately takes many tool rounds. Cancel aborts the stream and tells the runtime to stop the turn. +- In **Ask** and **Plan**, the tools that change things are simply absent: writing a file, editing a file, running a command, updating the task list and dispatching the background worker. Nothing asks the agent to hold back, because there is nothing to hold back with. If a call is attempted anyway it is refused a second time when it is dispatched. +- **Plan** adds the one tool that publishes a plan, which is the only thing that fills the **Plan** tab. +- **Agent** has the full set, including edits, commands, a branch and a pull request. -## Compaction +Because the catalogue is fixed when the turn is built, **a mode change takes effect on the next turn, not on the turn already running**. Switching to Agent halfway through does not retroactively let the running turn edit anything. The **Changes** pane says the same thing in the other two modes: **Ask and Plan do not change files, so there is nothing to review here.** See [Ask, Plan, Agent](/code/interactions). -Long sessions are compacted with Code's own keep-set — the current task, open files, recent diffs — so the model keeps fitting in context. Compaction **fails closed**: an unavailable summariser is an error, not a silent loss of history. +## Two gates, two different words -## The CLI on top +Cortex asks for your consent in two distinct places, and they are not interchangeable. -The CLI drives the same session API with streaming tokens and first-class tool rows. It adds harness-side locks — Plan and Spec keep mutating tools blocked until you switch back or accept the plan — plus approvals, a sandbox policy, and a persisted long-horizon `/goal`. See [Modes and permissions](/cli/modes-and-permissions) and [Goals](/cli/goal). +| Gate | What it decides | What you press | +| --- | --- | --- | +| The prompt card above the transcript | whether a command may run | **Allow once**, **Always allow**, **Deny** | +| The **Changes** pane | whether a file is written | **Approve**, **Approve all**, **Reject** | -<Frame caption="A CLI session with an active goal: the composer border reads Agent — Goal · 2/8, and the agent keeps working toward it across turns."> - <img src="/images/cli/runtime/40x12/goal-chip-active.png" alt="Cortex CLI composer with the Goal chip, rendered in a 40 by 12 terminal" /> -</Frame> +**Always allow** is a grant for that tool in this session only. It is not an account setting, it does not carry to another session, to Chat or to the CLI, and **it never covers a file write**. Every write, in every session, waits for a human **Approve**. Until then the tree is not written. **Deny** refuses a call and the turn continues with the agent told it was denied; a denial is not a crash. -## Compared with Chat and Bot +Running commands is allowed or withheld as a whole. There is no per-command and no per-directory allowlist to configure, so the decision in front of you is the whole decision. -| | Chat | Code | Bot | -| --- | --- | --- | --- | -| Where tools run | Snippet sandbox | The session's guest | The bot's computer | -| Mutations gated by | — | Mode (Ask / Plan / Agent) | Approvals (Allow / Deny / Always) | -| Stops on | 8 tool rounds | Model stops or Stop | 15-minute deadline or six identical calls | -| Transcript | Streamed reply | Turn timeline | User-visible bubbles | +<Warning> +There is no undo, no checkpoint and no revert anywhere in Code. Nothing rolls a turn's edits back. The moment to refuse a change is while it is still pending in **Changes**, with **Reject**, where you can also record why so the agent reads it. +</Warning> -See [How Chat works](/chat/how-it-works) and [How Bot works](/bot/how-it-works). +See [Permissions and approvals](/code/approvals) and [Changes and diffs](/code/changes). + +## When the context fills up + +A long session eventually outgrows the model's context window. Cortex compacts the transcript and says so, with **Earlier turns were compacted**. When the window is already full it asks: **Context is full. Compact the session to continue.** On a draft that is too long to send, you choose **Keep in context** or **Compact anyway**. + +Compaction fails closed. If it cannot run the turn stops rather than silently dropping history, and you see **Compaction is not available on this deployment.** or **The session could not be compacted.** Long tool output is shortened in the transcript for the same reason: the turn keeps fitting. + +## Stopping a turn + +While a turn runs, the send disc in the follow-up box is a square. Pressing it posts a cancel on the session; it does not merely close the connection. + +The cancel is recorded once. Pressing **Stop** again while a cancel is already pending is refused as an invalid state rather than counted twice. The session then reads **Stopped** and offers **Continue**, which sends **Continue from where you stopped.** A turn that ended in error is a different thing: it reads **Failed** and offers **Try again**. Stopped is never drawn as a failure. + +Detaching is not stopping. **Detach** stops you watching and the turn carries on; you must **Attach** again to send a follow-up or to answer a decision. In **Focus** view, approvals still interrupt you. + +## What a Code session does not have + +- **No Chat tools.** Web search, web page extraction, the Python sandbox, skills and the clock are Chat's. A Code session runs the repository's own Python through a shell command instead. +- **No tool servers, connectors or plugins.** A Code turn is built with an empty dynamic toolset, so a session may report **Off · this session has no MCP access.** and **Off · Chat and Bot access does not carry into Code.** Servers you configure for the workspace do not become a session's tools. See [Code integrations](/code/integrations). +- **No nested agents in the browser.** The background worker a Cloud session can dispatch lists files and searches them; it is not a second agent with its own transcript. Nested transcripts belong to the Cortex desktop app. +- **No screen.** A Cloud guest is headless, and the session's **Desktop** tab carries the badge **Soon**. ## Related -- [Sessions](/code/sessions) — reading the timeline this loop produces. -- [Ask, Plan, Agent](/code/interactions) — the modes that gate mutating tools. -- [Cloud runtimes](/code/cloud) — the guest the tools execute in. -- [Code troubleshooting](/code/troubleshooting) — when the agent will not edit. +- [Code sessions](/code/sessions) for the board, the transcript and follow-ups. +- [Ask, Plan, Agent](/code/interactions) for what each mode may reach. +- [Permissions and approvals](/code/approvals) for both gates in detail. +- [Cloud runtimes](/code/runtimes) for the guest a turn attaches. +- [Code in the terminal](/code/cli) for the same loop from a terminal. diff --git a/code/index.mdx b/code/index.mdx index 9f5a4b5..17fbc9f 100644 --- a/code/index.mdx +++ b/code/index.mdx @@ -1,109 +1,175 @@ --- title: "Cortex Code" -description: "A coding agent that works inside your repository on an isolated runtime — sessions, Ask / Plan / Agent, GitHub, Cloud guests, and review." -image: "/images/banners/code.png" -keywords: ["coding agent", "repository", "developer"] +description: "Cortex Code is a coding agent that works in one repository inside an isolated Cloud guest, with a timeline you watch and changes you approve." +icon: "code" --- -Cortex Code is a coding agent, not a chat with a different icon. You point it at a repository, describe the change, and it works through the task inside an isolated runtime — reading, editing, running your build and tests — while you watch a timeline of what it did and decide how much it may do on its own. +Cortex Code is a coding agent, not a chat with a different icon. You point it at one repository, describe the change in plain language, and it works through the task inside an isolated runtime: reading files, editing them, running your build and your tests, while a timeline records what it did. You decide how much a turn may do on its own, and no file lands in the tree until a human approves it. -It is available in the web app, the desktop app, and the CLI, with one account across all three. - -<Frame caption="The four commitments on the public Code page: one repository per runtime, reviews that stay failed when they fail, no pasted diff, the same account as Chat."> - <img src="/images/product/code-public-features.png" alt="Cortex Code feature grid — One repository per runtime, Reviews that stay failed when they fail, No pasted diff, The same account as Chat" /> -</Frame> +Code is a mode of your Cortex account rather than a separate product. It runs in your browser, in the Cortex desktop app and in the Cortex CLI. This page says what Code is and is not, links every page in this tab, and marks the line where Code stops and Cortex Security or the CLI begins. ## What Code is | Commitment | What it means for you | | --- | --- | -| **One repository per runtime** | Each session gets an isolated guest on the same farm as Cortex Bot, without a desktop. The environment is installed by the agent, not guessed from a filename. | -| **Reviews stay failed when they fail** | A Cortex Security review is one pass over a diff. A failed review is stored as failed — never rewritten as an approval. | -| **No pasted diff** | Code writes the change in the repository; Cortex Security reads the pull request in place. Neither asks you to paste a patch into a box. | -| **The same account as Chat** | Sign in on cortex.foundation. No second identity. | +| **One repository per runtime** | A session works one repository at a time. A second repository is a second session. | +| **Reviews stay failed when they fail** | A failing check is not softened into a warning later. | +| **No pasted diff** | A change arrives as a branch and a pull request, never as a patch to copy out of a box. | +| **The same account as Chat** | One Cortex account across Chat, Code and the CLI. | ## Who can open it -Code is a member surface. A guest visiting `/code` sees the public product page, and deep links show **This space is reserved** with **Continue in Chat** or **Sign in**. Once signed in, `/code` opens Code Home: connect GitHub, pick a repository, start a session. See [Accounts](/getting-started/accounts). +Code is a member surface. A guest who visits the Code area sees the public product page, and a guest on a deep link sees **This space is reserved**, with **Continue in Chat** or **Sign in**. -<Frame caption="cortex.foundation/code — the public product page a guest sees. Sign in to open the working UI."> - <img src="/images/product/code-public.png" alt="Cortex Code public page — a coding agent that works inside the repository" /> -</Frame> +Once you are signed in, Code Home is the composer itself. Its heading reads **What should Cortex build?** and its prompt box reads **Ask Cortex to build, fix, explore.** A guest can type there, but pressing **Start session** opens the sign-in dialog. That is an invitation, not an error. ## Start here -<CardGroup cols={3}> - <Card title="Quickstart" img="/images/banners/code.png" href="/code/quickstart"> - Sign in, connect GitHub, start a Cloud session, review the timeline. +<CardGroup cols={2}> + <Card title="Code quickstart" icon="rocket" href="/code/quickstart"> + Sign in, connect GitHub, run a first Cloud session and approve the change it proposes. </Card> - <Card title="Sessions" icon="list" href="/code/sessions"> - A timeline of the work — files read, edits, commands, plans. + <Card title="How Code works" icon="diagram-project" href="/code/how-it-works"> + The turn loop in user terms: where tools run, what each mode withholds, how a turn ends. </Card> - <Card title="CLI" icon="terminal" href="/cli"> - The same Code sessions from your terminal, scripts, and CI. +</CardGroup> + +## Work in a session + +<CardGroup cols={2}> + <Card title="Code sessions" icon="list-check" href="/code/sessions"> + The session object, the board, the transcript, follow-ups and what survives a turn. + </Card> + <Card title="Ask, Plan, Agent" icon="sliders" href="/code/interactions"> + The three interaction modes, what each may reach, and switching per turn. + </Card> + <Card title="Permissions and approvals" icon="hand" href="/code/approvals"> + Allow once, Always allow and Deny for commands, plus the separate gate on file writes. + </Card> + <Card title="Changes and diffs" icon="code-compare" href="/code/changes"> + The Changes pane, a proposed diff before a write and a landed diff after it. + </Card> + <Card title="Tickets" icon="ticket" href="/code/tickets"> + Tickets as a unit of asynchronous work, and why they have no screen in the app yet. </Card> </CardGroup> -## Where it runs +## Where code runs -| Surface | Host | Notes | -| --- | --- | --- | -| Web app | **Cloud** | Web Code is Cloud-only | -| Desktop app | Cloud, **This PC**, **SSH** | [Code on desktop](/code/desktop) | -| CLI | Cloud by default; This PC and SSH by opt-in | [Code in the terminal](/code/cli) | +<CardGroup cols={2}> + <Card title="Cloud runtimes" icon="cloud" href="/code/runtimes"> + The isolated Cloud guest a session attaches, how it is prepared, and what happens without capacity. + </Card> + <Card title="Environments and images" icon="box" href="/code/environments"> + Running machines and saved images, so the next session on a repository skips the install. + </Card> + <Card title="Machines" icon="laptop" href="/code/machines"> + Cloud occupancy and team runners, and why desktop hosts are not offered in the browser. + </Card> + <Card title="SSH hosts" icon="server" href="/code/ssh-hosts"> + Register a remote host in the desktop app, then select it for a session from there or from the CLI. + </Card> + <Card title="Code on desktop" icon="desktop" href="/code/desktop"> + This PC and SSH exist in the desktop app and the CLI. The browser stays on Cloud. + </Card> +</CardGroup> -## Modes in one line +## Repositories -**Ask** reads and explains. **Plan** proposes without changing anything. **Agent** edits files and runs commands. Pick per turn; the session row holds the default. See [Ask, Plan, Agent](/code/interactions). +<CardGroup cols={2}> + <Card title="Connect GitHub" icon="github" href="/code/github"> + One control, no tokens to paste, and what to do when a connection lapses. + </Card> + <Card title="Repositories and branches" icon="code-branch" href="/code/repositories"> + Pick the repository and the base branch, and work in the session's own isolated worktree. + </Card> +</CardGroup> -## Core guides +## Automate and monitor <CardGroup cols={2}> - <Card title="Sessions" icon="list" href="/code/sessions"> - A session is a timeline of the work — files read, edits, commands, plans — with Stop always one click away. + <Card title="Automations" icon="bolt" href="/code/automations"> + Saved instructions with a trigger, a repository and a prompt, and what a run does today. </Card> - <Card title="Ask, Plan, Agent" icon="sliders-horizontal" href="/code/interactions"> - Choose how much a turn may change. Ask reads, Plan proposes, Agent edits and runs. + <Card title="Code notifications" icon="bell" href="/code/notifications"> + The inbox that tells you when a session finished or needs a decision. </Card> - <Card title="Connect GitHub" icon="github" href="/code/github"> - Reach repositories through Connect GitHub. No pasted tokens; Reconnect when a grant lapses. + <Card title="Usage" icon="chart-simple" href="/code/usage"> + Recorded cost and billable actions over a 7, 30 or 90 day window. </Card> - <Card title="Cloud runtimes" icon="cloud" href="/code/cloud"> - One isolated guest per session on the same farm as Bot, prepared by the agent. +</CardGroup> + +## Configure + +<CardGroup cols={2}> + <Card title="Code settings" icon="gear" href="/code/settings"> + Default model and fallback models, and the settings that are not configurable yet. + </Card> + <Card title="Code integrations" icon="puzzle-piece" href="/code/integrations"> + Connected apps, repositories and tool servers for the workspace. </Card> </CardGroup> -## Desktop and terminal +## Reference <CardGroup cols={2}> - <Card title="Code on desktop" icon="monitor" href="/code/desktop"> - This PC and SSH hosts exist on the desktop app and the CLI. The browser stays Cloud-only. + <Card title="Code in the terminal" icon="terminal" href="/code/cli"> + The same sessions from a terminal, and how CLI words map onto Code words. + </Card> + <Card title="Pull-request review" icon="shield-halved" href="/code/security"> + Where Cortex Security sits under Code, and which tab documents it. </Card> - <Card title="Code in the terminal" icon="square-terminal" href="/code/cli"> - How the CLI maps onto Code sessions, and where the full CLI documentation lives. + <Card title="Code troubleshooting" icon="life-ring" href="/code/troubleshooting"> + Gates that will not open, a runtime that is unavailable, and modes that will not edit. </Card> </CardGroup> -## What Code is not +## Where a session runs -| Not this | Use instead | +| Surface | Runtimes offered | | --- | --- | -| A Chat transcript | A [session](/code/sessions) is a turn timeline — files read, edits, commands, plans | -| Chat's Python sandbox | [Cloud runtimes](/code/cloud) — an isolated guest with your repository | -| A Chat plugin | [Connect GitHub](/code/github) — the repository connection lives in Code | -| The public `/security` page | [Cortex Security](/code/security) — the signed-in review inbox at `/code/security` | -| A place to store secrets | There is no Secrets page. Environment for a guest belongs to that guest; `/code/secrets` sends you home. | +| Browser | **Cloud**, plus a registered team runner when the deployment has one | +| Desktop app | Cloud, **This PC**, **SSH** | +| Cortex CLI | Cloud by default; This PC and SSH by opt-in | + +Everything a turn does happens inside the runtime it attached. Nothing runs in your browser. + +## Modes in one line + +**Ask** answers questions and reads files. **Plan** writes a reviewable plan. **Agent** edits files, runs commands and opens a pull request. The choice is a lock on the tools the turn is built with, so a change applies to the next turn, not to the turn already running. The composer's fourth row, **Security**, is not a fourth mode: it leaves for Cortex Security. See [Ask, Plan, Agent](/code/interactions). + +## Two gates, and they are not the same + +A command that needs a decision raises a card above the transcript with **Allow once**, **Always allow** and **Deny**. A file write never uses that card: it waits in the **Changes** pane for a human **Approve**, per file or as **Approve all**, and a session-level **Always allow** never covers a write. + +<Warning> +There is no undo, no checkpoint and no revert anywhere in Code. The moment to refuse a change is while it is still pending in **Changes**, with **Reject**. See [Permissions and approvals](/code/approvals). +</Warning> + +## What Code is not + +- Not a hosted development environment. There is no screen in a Code runtime. +- Not a place to store secrets. Code has no Secrets page and never asks you to paste a token. +- Not a continuous integration system. It runs your commands in a session, on request. +- Not a chat about your code. It edits the repository and opens pull requests. + +## Not available yet + +- **Tickets** have no screen in the app; they are an API level concept today. +- A session's **Desktop** tab is drawn with the badge **Soon**. +- Automations are saved instructions only: **Schedules and events do not execute yet.** +- A Code session has no tool servers, connectors or plugins of its own, so do not plan work around attaching one to a session. See [Code integrations](/code/integrations). -## Advanced +## How it fits with the other products -- [Cortex Security](/code/security) — GitHub App pull-request review that stays failed when it fails. -- [How Code works](/code/how-it-works) — workspace tools execute inside the attached guest; modes withhold mutating tools. -- [Code troubleshooting](/code/troubleshooting) — gates, Reconnect, Cloud availability, and what a failed review means. -- [Security and privacy](/security/overview) — what Cortex stores and where code runs. +- **Cortex Chat** shares the account and the sidebar. Chat talks about your code; Code changes it. See [Cortex Chat](/chat/index). +- **The Cortex CLI** drives the same sessions from a terminal, and a session it started is marked **· Started from CLI** on the board. See [Code in the terminal](/code/cli) and [Cortex CLI](/cli/index). +- **Cortex Security** reads a pull request and posts a review; it lives under Code in the app and is documented in its own tab. See [Pull-request review](/code/security) and [Cortex Security](/security/index). -## Next +## Related -1. [Code quickstart](/code/quickstart) — sign in, connect GitHub, start a Cloud session. -2. [Sessions](/code/sessions) — read the timeline. -3. [Ask, Plan, Agent](/code/interactions) — decide how much a turn may change. -4. [Code in the terminal](/code/cli) — the same sessions from the CLI. +- [Code quickstart](/code/quickstart) for a first session end to end. +- [How Code works](/code/how-it-works) for cause and effect in a turn. +- [Code sessions](/code/sessions) for the board and the transcript. +- [Permissions and approvals](/code/approvals) for the two gates in full. +- [Code troubleshooting](/code/troubleshooting) when something will not start. diff --git a/code/integrations.mdx b/code/integrations.mdx new file mode 100644 index 0000000..7375039 --- /dev/null +++ b/code/integrations.mdx @@ -0,0 +1,87 @@ +--- +title: "Code integrations" +sidebarTitle: "Integrations" +description: "The Integrations page: connected apps, repositories, MCP servers and API keys, and the important limit on what a Code session can actually reach." +icon: "puzzle-piece" +--- + +**Integrations** is the page where you connect outside services to Cortex. It invites you in with **Connect the tools your sessions need to reach.**, and it is the right place to connect GitHub and to register an MCP server for your workspace. + +Read the next paragraph before you connect anything, because the page's invitation is broader than what a Cortex Code session can use today. + +<Warning> +**Tools connected here do not reach a Code session today.** A Code turn is built with an empty tool catalog for outside tools, so a Code session is given no MCP servers, no connected apps and no plugins. The session will tell you so itself: its **Tools** tab can read **Off · this session has no MCP access.** and **Off · Chat and Bot access does not carry into Code.** Connected apps do work elsewhere, in [Connectors](/chat/plugins) for Cortex Chat and in [Connected apps and secrets](/bot/plugins) for a bot. Treat this page as workspace configuration, and never plan a Code session around a tool you connected here. +</Warning> + +The one thing on this page that genuinely changes what a Code session can do is the GitHub connection, because that is what gives Code repositories to work in and the ability to open a pull request. Everything else is configuration held for the workspace. + +## The sections of the page + +| Section | What it holds | +| --- | --- | +| **CONNECTED APPS** | Apps from the connector marketplace that Cortex can sign you in to. | +| **REPOSITORIES** | The repositories your GitHub connection exposes. | +| **MCP SERVERS** | Servers you register for the workspace by name and URL. | +| **API keys** | Programmatic access for your account. | + +## Connected apps + +An app on this page is in one of two states, and there are only two. Either Cortex can connect it, or it renders **Not connectable**, which means its tools exist but Cortex has no sign-in for it yet. There is no third option, and in particular **there is no token method for a connected app**: you cannot make an app connectable by pasting a credential. + +At least one app in the list is not connectable yet. That row is doing what it should, so do not read it as a fault or an outage on your side. + +<Note> +An MCP server's optional bearer token is a different thing entirely and stays. Aside from that one field, no Code surface asks you to paste a credential: there is no personal access token field anywhere, and Code has no Secrets page. +</Note> + +## Repositories + +The **REPOSITORIES** section is a view of your GitHub connection rather than a separate setting, and its empty copy tells you which of three situations you are in. + +| What you read | What it means | +| --- | --- | +| **GitHub returned no repositories for this account.** | GitHub is connected, and it reported nothing. Check what the connection was granted on GitHub's side. | +| **No repositories to show yet.** | GitHub is not available to connect on this deployment. | +| **Connect GitHub and your repositories appear here.** | You have not connected GitHub yet. | + +**Connect GitHub** is a single control with a single label, and it appears here, in the composer's repository picker, in the dashboard checklist and in Settings. If the connection has lapsed it reads **Reconnect GitHub** instead and says so. When GitHub is connected there is no control and no note, and on a deployment without GitHub the control is simply absent rather than greyed out. For the whole flow, including what to do when a connection attempt does not finish, see [Connect GitHub](/code/github). + +<Info> +The connection Code uses is not the only GitHub install Cortex offers. Cortex Security's GitHub App is a separate install that lets it read pull requests and post checks, and the Cortex CLI has its own install command. Connecting one does not connect the others. See [Pull-request review](/code/security) and [Code in the terminal](/code/cli). +</Info> + +## MCP servers + +You register an MCP server with three fields. + +<Steps> + <Step title="Name it"> + **Name** is the label you will recognise the server by. + </Step> + <Step title="Give it a URL"> + **URL** is the server's address. + </Step> + <Step title="Add a token if it needs one"> + **Auth token** is optional. Its own hint is the guarantee worth reading: **Sent as a bearer token on every call. Sealed on the server.** Once saved it is never read back into the form, so keep your own copy if you need it again. + </Step> +</Steps> + +A registered server is configuration held for the workspace. Whether a given surface can reach it is decided by that surface, and a Code session reports its own answer on its **Tools** tab, where rows read **On**, **Off** or **Organization denied**. A session with nothing available shows **No tool servers on this session.** For MCP in a surface where it is used today, see [MCP servers](/chat/mcp-servers). + +## API keys + +The **API keys** section exists on this page for programmatic access to your account. How a key is created, shown or revoked here is not documented, so work from the section in the app rather than from an expectation set here. + +## What is not available + +- **MCP servers, connected apps and plugins in a Code session.** Configured here, not given to a Code turn. This is the limit to plan around. +- **Scoping a server to one repository**, and any per-workspace server limit shown to you, are not documented. No number is shown on this page. +- The full list of connectable apps changes with the connector marketplace, so read the page rather than a list in the docs. + +## Related + +- [Connect GitHub](/code/github) +- [Repositories and branches](/code/repositories) +- [Code settings](/code/settings) +- [Connectors](/chat/plugins) +- [Connected apps and secrets](/bot/plugins) diff --git a/code/interactions.mdx b/code/interactions.mdx index 05f33c1..eb6a691 100644 --- a/code/interactions.mdx +++ b/code/interactions.mdx @@ -1,55 +1,82 @@ --- title: "Ask, Plan, Agent" -description: "Choose how much a Code turn may change. Ask reads and explains, Plan proposes, Agent edits and runs. The choice rides on the turn." -keywords: ["Ask", "Plan", "Agent", "modes", "permissions"] +description: "Ask reads and explains, Plan proposes, Agent edits and runs. The mode locks the tools a turn is built with and applies to the next turn." +icon: "sliders" --- -Every Code turn runs in one of three modes. Pick it on the turn, or leave the session's default. A follow-up can pick a different mode — tighten to Ask to understand, widen to Agent to ship. +Every turn in Cortex Code runs in one of three interaction modes. **Ask** answers questions and reads the repository. **Plan** returns a plan you can review. **Agent** edits files, runs commands and opens a pull request. You pick the mode in the composer before you start a session, and again on every follow-up, so a single session can tighten to Ask to understand something and widen to Agent to carry it out. + +This page explains what each mode may reach, why the choice is worth trusting, when the change takes effect, and what none of the three modes can do. If you are looking for a first session end to end, start with the [Code quickstart](/code/quickstart). ## What each mode may do -| Mode | Edit files | Run commands | What it produces | -| --- | --- | --- | --- | -| **Ask** | No | No | Explanations, answers, code you can copy | -| **Plan** | No | No | A plan block — steps, and a mermaid diagram when it helps | -| **Agent** | Yes | Yes | Changes in the repository, with diffs and command output on the timeline | +| Mode | Its own description in the app | Edits files | Runs commands | What it produces | +| --- | --- | --- | --- | --- | +| **Ask** | **Questions and exploration. Nothing is edited until you switch to Agent.** | No | No | Answers, file reads, searches | +| **Plan** | **A mermaid plan you can review. No edits until you switch to Agent.** | No | No | A reviewable plan on the **Plan** tab | +| **Agent** | **Full catalog: read, edit, run, and open a pull request.** | Yes | Yes | Edits, command output, a branch and a pull request | + +All three modes can read a file, list files by pattern, search the repository by regular expression, read the task list and read artifacts. Only **Agent** can write a file, edit a file, run a command, write the task list, or dispatch the background search worker. + +## The lock is on the tools, not on the model + +The three modes are worth trusting because of where the decision is made. In Ask and Plan the mutating tools, writing, editing, running a shell command, writing the task list and dispatching the background worker, are simply **absent** from the catalog the turn is built with. The model is not asked to behave: there is no instruction it could misread or talk itself out of, because the tool is not there to call. If one is called anyway, the call is refused a second time when it is dispatched. + +Plan gets one extra tool the others do not: the plan writer. That is the only thing that fills the **Plan** tab. + +<Warning> +Because the catalog is chosen when the turn is built, **a mode change takes effect on the next turn, not on the turn already running.** Switching to Agent while a turn is in flight does not retroactively let that turn edit anything, and switching to Ask does not claw back an edit the running turn has already proposed. If you need a running turn to stop, press **Stop** in the composer's send disc, then send the next turn in the mode you want. +</Warning> + +## Choose a mode, and change it per turn + +<Steps> + <Step title="Pick the mode for the first turn"> + On Code Home, the controls row under the prompt carries **Ask**, **Plan** and **Agent**. The mode is stored on the session, and a new session defaults to **Agent**. + </Step> + <Step title="Send the task"> + Press **Start session**. The turn is built with the catalog that mode allows, and nothing widens it afterwards. + </Step> + <Step title="Change it on a follow-up"> + The follow-up composer inside the session carries the same mode menu, so the mode can change on every turn. Pick a mode and send the follow-up: the new mode applies to that turn. A follow-up that does not pick one keeps the session's current mode. + </Step> +</Steps> + +A useful rhythm: **Plan** to agree on the approach, **Agent** to carry it out, **Ask** when something has gone sideways and you want to understand the repository before you let anything else change. + +## What a Plan turn gives you -Ask and Plan **withhold the mutating tools**. That is enforced by the harness, not by asking the model to behave: in those modes the edit and shell tools are not offered at all. Plan writes its proposal through a dedicated plan tool. Agent receives the full workspace catalog inside the guest. See [How Code works](/code/how-it-works). +A Plan turn reads the repository and returns a structured proposal: titled steps, the files it expects to touch, the risks it sees, and a rendered diagram. The product's own word for the diagram is mermaid, which is why the mode's description mentions it. -## When to use which +The **Plan** tab in the output pane appears **only when the session has a plan**. Nothing changes in the repository while you read it. Ask for adjustments as many times as you like, in Plan, and send an **Agent** turn when the approach is right. The cheap moment to redirect a change is before any file moves. -| Situation | Mode | -| --- | --- | -| Unfamiliar code, *how does this work?* | **Ask** | -| Estimating a change, reviewing an approach before anything moves | **Plan** | -| A change you have already decided on | **Agent** | -| Something went sideways and you want to understand before continuing | Follow up in **Ask**, then return to **Agent** | +## Ask and Plan in the Changes pane -## How to pick +The **Changes** pane is where file writes wait for a human decision. In Ask or Plan there is nothing there to decide, and the pane says so outright: -1. Choose **Ask**, **Plan**, or **Agent** on the turn. The session row's setting is the default for new turns. -2. Send the task. -3. On a follow-up, change mode if you want a tighter or looser loop. +> **Ask and Plan do not change files, so there is nothing to review here.** -Web Code has no model picker: the web app is Cloud-only and the runtime chooses the model. In the CLI, `/model` picks the model and the reasoning effort, `/mode` and **Shift+Tab** switch Agent / Plan / Ask, and `/plan` drafts a plan before any code is written — see [CLI modes and permissions](/cli/modes-and-permissions). +That is the mode reporting itself, not a failure. See [Changes and diffs](/code/changes). -<Frame caption="The CLI's slash palette in a small terminal: /plan drafts a plan before writing, /goal keeps a long-horizon objective."> - <img src="/images/cli/runtime/40x12/slash-palette.png" alt="Cortex CLI slash palette showing /plan and /goal in a 40 by 12 terminal" /> -</Frame> +## Security is not a fourth mode -## Plan in practice +Under the three modes there is a fourth row labelled **Security**, with the hint **Open Security mode for this repository**. It is a link, not a mode: it leaves the composer for Cortex Security, which reads a pull request and posts a review instead of writing code. A session's interaction stays Ask, Plan or Agent. See [Pull-request review](/code/security). -A Plan turn reads the repository and returns a structured plan: the steps it would take, the files it would touch, the risks it sees. Nothing changes until you send an Agent turn. Ask for adjustments in Plan as many times as you like — the cheap moment to redirect is before any file moves. The CLI adds a **Spec** lock on top of Plan that keeps mutating tools blocked until you accept the plan; see [CLI modes](/cli/modes-and-permissions). +## What no mode can reach -## Modes are a harness lock, not a promise +<Note> +The mode is chosen **per session and per turn only**. There is no workspace setting that pins a read-only default, and [Code settings](/code/settings) does not offer one. If you want a session to stay in Ask, keep choosing Ask on each turn. +</Note> -The three modes are worth trusting because of where the decision is made. Ask and Plan do not receive the editing and shell tools at all, so there is no instruction the model could follow, misread, or talk itself out of — the tools are simply absent from the request. That is also why a mode change takes effect on the next turn rather than mid-turn: the tool set is chosen when the turn is built. +A Code session does not receive the tools a Chat turn has: no web search, no web page extraction, no hosted snippet sandbox, no skills and no clock. When a task needs to run your repository's own Python, an Agent turn runs it as a shell command inside the attached runtime, like any other command. -In Agent, the mode is not a safety net. The agent runs the full workspace catalog inside the guest, which is why the guest is isolated, why approvals exist in the CLI, and why the timeline keeps the diff. Read what it did before your next turn. +A Code session is also built with no tool servers, connectors or plugins of its own, so widening the mode to Agent does not open a path to an external service. See [Code integrations](/code/integrations) for what is configured at the workspace level and what a session reports. ## Related -- [Sessions](/code/sessions) — where the turns live. -- [Code quickstart](/code/quickstart) — a first Plan, then Agent. -- [How Code works](/code/how-it-works) — the catalog each mode receives. -- [Code troubleshooting](/code/troubleshooting) — a mode that will not edit. +- [Code sessions](/code/sessions) for the transcript, follow-ups and the session board. +- [How Code works](/code/how-it-works) for the turn loop the mode is built into. +- [Permissions and approvals](/code/approvals) for the two gates an Agent turn meets. +- [Changes and diffs](/code/changes) for reading and approving what an Agent turn proposes. +- [Modes and permissions in the CLI](/cli/modes-and-permissions) for the same choice in a terminal. +- [Code troubleshooting](/code/troubleshooting) when a turn will not edit anything. diff --git a/code/machines.mdx b/code/machines.mdx new file mode 100644 index 0000000..4c0e63c --- /dev/null +++ b/code/machines.mdx @@ -0,0 +1,78 @@ +--- +title: "Machines" +description: "What the Machines page shows: Cloud occupancy and team runners, why your paired desktop machine is not listed, and what to do instead." +icon: "laptop" +--- + +**Machines** is a small page in Cortex Code, and its name promises more than it delivers. Its own lede is the honest summary: **Cloud occupancy and team runners. Offline stays on Cloud.** It answers one question, which is what compute this workspace can currently place a session on. + +It is not an inventory of every computer you own. If you paired your own machine with the Cortex desktop app, it will not appear here. This page explains what the list does contain, why your desktop host is absent, and the three states you are most likely to see instead of a populated list. + +## What the page lists + +The page lists Cloud occupancy and any **team runner** the deployment has registered, and nothing else. For each row it shows the machine class, the toolchain it carries, and the fact that the guest is headless: there is no screen, no desktop and no remote-desktop view in a Code runtime, wherever the code runs. + +Rows carry one of two states: + +| Row state | What it means | +| --- | --- | +| **Idle** | The machine is registered and available | +| **Active** | The machine is in use | + +The page's one action is **Use Cloud**, which sends you back to starting a normal session. + +## Your own machine is not here + +**Desktop hosts are never listed on this page.** Pairing a machine in the Cortex desktop app makes **This PC** available as a runtime in that app, and it does not register a machine that the browser can see or attach to. Do not come here to check whether your laptop is connected: read the harness state in the desktop app instead, described on [Code on desktop](/code/desktop). + +This is also what **Offline stays on Cloud** means. Your own machine going offline does not move a Cloud session anywhere, and it does not stop one: a session that was placed on a Cloud guest keeps running on that guest regardless of what your laptop is doing. In the desktop app, a session that is alive in the cloud while the local harness is down reads **Cloud session running** for exactly this reason. + +## Choosing where a session runs + +You do not pick a machine on this page. You pick it in the composer, under **Run on**, before you press **Start session**: + +| Row | What it is | +| --- | --- | +| **Cloud** | **Isolated guest on Cortex Cloud.** The default, and the only runtime the browser always has | +| **Team pool · live** | A registered team runner that is reachable now | +| **Team pool · offline** | A registered team runner that is not reachable | +| **Machines** | The picker's own row for this page | + +A session binds one runtime, once per turn, with no fallback. If the runtime you chose cannot be used, the turn refuses and names an action to take rather than quietly running your repository somewhere you did not choose. Nothing silently downgrades a team runner to Cloud, and nothing silently promotes a Cloud session onto a runner. + +## The three states you will usually see + +On most deployments there is no team runner at all, so an empty list is the normal, healthy state rather than a failure: + +| What you see | What it means | What to do | +| --- | --- | --- | +| **No live machines** and **Use Cloud until a team runner is live.** | No runner is reachable. This is the usual state | Press **Use Cloud** and start the session normally | +| **Machines are not on this deployment** and **This deployment has no runners route. Sessions still run on Cloud.** | The capability is not enabled here at all. This is not an upgrade prompt | Nothing. Cloud sessions are unaffected | +| **Sign in to see machines** and **A guest cannot attach a runner.** | You are browsing signed out | Sign in with your Cortex account | + +<Note> +If you were expecting a list and got **No live machines**, nothing is broken. Cloud is the runtime for browser sessions, and the page exists to tell you whether anything else is available, not to be filled. +</Note> + +## What a machine does not change + +Where a session runs changes which files the tools touch. It does not change how Cortex asks for your consent, and it does not give you a rollback: + +- **A command is answered per command, as it is asked.** There is no command allowlist and no per-directory allowlist anywhere in Cortex Code, on any machine. You answer **Allow once**, **Always allow** or **Deny** for the call in front of you. See [Permissions and approvals](/code/approvals). +- **A file write is approved somewhere else.** Writes never appear on that rail. They wait in **Changes** for a human **Approve**. See [Changes and diffs](/code/changes). +- **There is no undo, no checkpoint and no revert.** A write is either rejected while it is still pending, or it lands. Moving a session to a different machine does not give you a state to go back to. +- **A Code session has no MCP servers, no connected apps and no plugins**, on any machine. The session's **Tools** tab says so itself: **Off · Chat and Bot access does not carry into Code.** + +## Capacity, and what it is not + +When no machine can be placed, Cortex fails closed and says so: nothing was started, so nothing was lost. The codes behind that are [`no_capacity`](/problems/no_capacity) when nothing could be placed, [`concurrency_limit_reached`](/problems/concurrency_limit_reached) when too many sessions are active at once, and [`service_unavailable`](/problems/service_unavailable) when the fleet is not answering. None of these means your repository is at fault, and none of them leaves a half-started session behind. + +Occupancy figures on this page describe the deployment's compute, not your account's allowance. For what your account can keep placed, see the environment and image ceilings on [Environments and images](/code/environments); for what has been recorded against your workspace, see [Usage](/code/usage). + +## Related + +- [Cloud runtimes](/code/runtimes) - the guest a browser session actually runs in. +- [Environments and images](/code/environments) - machines you keep, and the slot each one holds. +- [SSH hosts](/code/ssh-hosts) - a remote host, registered in the desktop app. +- [Code on desktop](/code/desktop) - where **This PC** lives, and how its state is shown. +- [Code troubleshooting](/code/troubleshooting) - sessions that will not start. diff --git a/code/notifications.mdx b/code/notifications.mdx new file mode 100644 index 0000000..6438fbb --- /dev/null +++ b/code/notifications.mdx @@ -0,0 +1,62 @@ +--- +title: "Code notifications" +sidebarTitle: "Notifications" +description: "The Notifications inbox: everything Cortex has told you about, newest first, with one row per thing that happened and one button to clear them." +icon: "bell" +--- + +**Notifications** is where Cortex tells you what happened while you were not watching. A Cortex Code session can run for a long time, and the whole point of starting one is that you go and do something else, so the inbox exists to bring you back at the two moments that matter: when a run finished, and when it is stuck waiting on a decision only you can make. + +This page explains what lands in the inbox, how to read and clear it, and what the inbox deliberately does not do. It is a list, not a settings screen: there is nothing to configure here. + +## One inbox for the whole product + +The most useful thing to know before you open it: **this is one inbox for the whole product, not a Code filter.** Despite living under Code in the app, the list is shared. Cortex Code runs, prompts from a bot that need an answer from a human, scheduled task results and machine wake failures all arrive in the same column, newest first. + +So do not expect a page that shows only your sessions. Read it as "everything Cortex has told you about", which is exactly how the page describes itself: + +> **Everything Cortex has told you about, newest first.** + +When something is unread, that line is replaced by a count, `{n} unread, newest first.` + +Every row links to whatever it is about. Depending on which identifier the notification carries, following a row takes you to a session, to a conversation, or to a bot. There is no separate detail view for a notification itself: the row exists to hand you back to the thing that needed you. + +## What Cortex tells you about + +The empty state is the clearest statement of the inbox's job, and it is worth taking literally: + +> **Cortex tells you when a session finishes, when it needs a decision, and when an automation ran.** + +Those three clauses map onto the work you actually do in Code. A finished session means there is a diff to read or a pull request to open, so see [Changes and diffs](/code/changes). A session that needs a decision is waiting on you in the approval rail or in the **Changes** pane, so see [Permissions and approvals](/code/approvals). An automation that ran has prepared a session you can open, so see [Automations](/code/automations). + +<Note> +The inbox draws **no per-kind label** on a row. There is no badge or heading anywhere in the list that reads "session finished" or "needs decision", so do not go looking for a way to see or filter by notification type. Read the row's own text and follow it. +</Note> + +## Clearing the list + +Rows arrive newest first and stay in that order. There is a single control: + +- **Mark all read** appears only when something is unread. Press it and the unread count goes away. +- If that does not work, Cortex says so plainly: **They could not be marked read**. Nothing was lost; try again. + +When the list has never had anything in it, the page shows **Nothing yet** with the three-clause sentence above and a **Start a session** button that takes you to Code Home. + +## What this page does not do + +Be aware of the gaps before you plan a workflow around the inbox. + +- There is no preference, mute or per-category control on this page. It reports; it does not configure. [Code settings](/code/settings) has model defaults and pointers, and no notification fields. +- Email and push delivery are not documented for this inbox. Treat the page in the app as the place notifications live. +- **Mark all read** is the only read control described here. Whether an individual row can be marked read on its own is not documented. +- How long a notification is kept is not documented. If a run matters, open the session and read it there rather than relying on the row still being in the list later. + +If a notification points at a session that will not open, or a run you expected never announced itself, work through [Code troubleshooting](/code/troubleshooting). + +## Related + +- [Code sessions](/code/sessions) +- [Permissions and approvals](/code/approvals) +- [Automations](/code/automations) +- [Code settings](/code/settings) +- [Notifications](/getting-started/notifications) diff --git a/code/quickstart.mdx b/code/quickstart.mdx index e109efb..470ae0f 100644 --- a/code/quickstart.mdx +++ b/code/quickstart.mdx @@ -1,51 +1,95 @@ --- title: "Code quickstart" -description: "Sign in, connect GitHub, start a Cloud session on a repository, and read the timeline — in the web app." -image: "/images/banners/code.png" -keywords: ["tutorial", "first session", "getting started", "repository"] +description: "Sign in, connect GitHub, start a Cloud session on a repository, read the timeline and approve your first change." +icon: "rocket" --- -This quickstart uses the web app, where Code runs in the Cloud. For This PC or SSH, use the [desktop app](/code/desktop) or the [CLI](/cli/quickstart). +This quickstart takes you from a signed-out browser to a first approved change, using Cortex Code in the Cloud. It should take under ten minutes of your attention, most of which is reading what the agent proposes. -<Frame caption="What a guest sees on a Code deep link. Sign in to open Code Home."> - <img src="/images/product/code-home.png" alt="Cortex Code guest gate — This space is reserved for signed-in accounts" /> -</Frame> +Everything here happens in the browser, where a session runs in an isolated Cloud guest. If you want a session to work on files on your own machine or on a server you own, that lives in the Cortex desktop app and the Cortex CLI instead; see [Code on desktop](/code/desktop). <Steps> <Step title="Sign in"> - Open [cortex.foundation](https://cortex.foundation) and sign in from the sidebar footer. Then choose **Code** in the product switcher. If you see **This space is reserved**, you are still a guest — choose **Sign in**. + Open the Cortex app at [cortex.foundation](https://cortex.foundation) and sign in with your Cortex account, then switch to Code. + + A guest can browse Code Home and type in the prompt box. Pressing **Start session** while signed out opens the sign-in dialog rather than failing, and a deep link into Code shows **This space is reserved** with **Continue in Chat** or **Sign in**. </Step> <Step title="Connect GitHub"> - On Code Home choose **Connect GitHub** (also in the repository picker and under **Settings → Integrations**). Approve the connection on GitHub. There is no personal-access-token field. If the button reads **Reconnect**, an earlier grant lapsed — reconnect and continue. See [Connect GitHub](/code/github). + Press **Connect GitHub** and approve the request on GitHub's own screen. The control appears on the Code integrations page, under **Settings → Integrations**, and straight from the repository picker when it would otherwise show an empty list. There is **no token to paste** anywhere in this step, and no field asking for one. + + When you come back, the page reads **GitHub is connected. Taking you back…** and returns you to where you started. If the control reads **Reconnect GitHub**, an earlier connection lapsed: press it and repeat. See [Connect GitHub](/code/github). </Step> - <Step title="Pick a repository and start a session"> - Choose a repository. Cortex starts a Cloud guest for it, attaches, and prepares the environment — the agent installs what the repository needs. Web Code is Cloud-only; you do not pick a host here. + <Step title="Pick a repository and a branch"> + Above the prompt box there are two chips. The first is **Choose a repository**. The second is **Branch**: leaving it alone uses the repository's own default branch. + + One session works one repository. If your change spans two repositories, that is two sessions. See [Repositories and branches](/code/repositories). </Step> - <Step title="Choose a mode and describe the change"> - Pick **Ask**, **Plan**, or **Agent** on the turn. Start with **Plan** if you want to see the approach before anything changes, or **Agent** to let it work. + <Step title="Choose a mode"> + The controls row carries three modes. + + | Mode | Its own description in the app | + | --- | --- | + | **Ask** | **Questions and exploration. Nothing is edited until you switch to Agent.** | + | **Plan** | **A mermaid plan you can review. No edits until you switch to Agent.** | + | **Agent** | **Full catalog: read, edit, run, and open a pull request.** | + + For a first run that ends in a real change, pick **Agent**. Pick **Plan** if you would rather read the approach first, then send a second turn in **Agent** to carry it out. The mode you pick applies to the turn you are about to send, and you can change it on every follow-up. + </Step> + <Step title="Describe the change and press Start session"> + Write the task the way you would write it for a colleague who has not seen the code yet. A good first ask: ```text Add a /healthz endpoint that returns 200 with the build version, and cover it with a test. ``` + + Press **Start session**. Cortex creates the session, opens it, and the first turn attaches an isolated Cloud guest prepared from the repository you chose. The first session on a repository spends time installing what the repository declares, so it is slower than the next one; a saved image removes that wait later. See [Environments and images](/code/environments). </Step> <Step title="Read the timeline"> - The session shows files read, edits made, commands run, and the plan when there is one — as it happens, not a bubble dump afterwards. The header shows run state; **Stop** cancels the live turn. Follow up with another turn in the same session, switching mode if you want a tighter or looser loop. + The transcript shows your ask as the **Task** line, then a row per piece of work with a duration: **Read**, **Edited**, **Ran** and **Worked**. Before anything has run it says **Nothing has run in this session yet. Describe a task below and Cortex will start work.** + + Long finished output is folded to keep the column readable. The hint says it plainly: **Long finished results are folded. Press Ctrl+O to expand every row.** On a Mac, Ctrl+O or Command+O both work. + + If the agent wants to run a command that needs your decision, a card appears above the transcript with **Allow once**, **Always allow** and **Deny**. **Always allow** applies to that tool in this session only. It is not an account setting, and it never covers a file write. </Step> - <Step title="Ship"> - Ask the agent to commit and open a pull request, or review the diff yourself. If your repository has [Cortex Security](/code/security) installed, the pull request gets a review as a GitHub check run. + <Step title="Approve the changes"> + Open the **Changes** tab in the output pane on the right. Each file the agent touched is listed with its state: **Queued**, **Writing**, **Pending**, then **Written**. + + Press **Approve** on a file you have read, or **Approve all** for the batch. Press **Reject** to refuse one, and where the surface offers it, say why under **Why reject this write** so the agent reads your reason. Until a file is approved, the tree is not written. + + In **Ask** or **Plan** this pane says so instead: **Ask and Plan do not change files, so there is nothing to review here.** + </Step> + <Step title="Ship it"> + Open the **Git** tab. Once the session has a branch it offers **Open pull request**; before that it reads **No branch yet** or **No pull request**. Pushes are limited to Cortex branches, so a session cannot push over your default branch. + + If the repository has pull-request review enabled, the review arrives on the pull request itself. See [Pull-request review](/code/security). </Step> </Steps> +## Read the change before you approve it + +**Approve** is the point of no return. There is no undo, no checkpoint and no revert anywhere in Code, and approving a file cannot be taken back from inside the session. While a write is still **Pending** you can **Reject** it; afterwards the repository is the only place to change your mind. + +This is also why the two gates use different words. The **Allow once** / **Always allow** / **Deny** card decides whether a command may run. The **Approve** in **Changes** decides whether a file is written. A session grant on the first never grants the second. See [Permissions and approvals](/code/approvals). + ## What to try next | Goal | Do this | | --- | --- | | Understand an unfamiliar area | An **Ask** turn: *Explain how requests are authenticated in this service.* | -| Estimate a change without touching anything | A **Plan** turn: the agent writes a plan with a mermaid diagram | -| Work from your own machine | Install the [desktop app](/getting-started/desktop) and choose **This PC** | -| Automate in CI | `cortex exec --auto read-only --git-diff "review this diff"` — see [Headless runs](/cli/headless) | +| See the approach before anything changes | A **Plan** turn, then read the **Plan** tab and send a follow-up in **Agent** | +| Keep the session going | Type in the follow-up box at the bottom of the transcript; Enter sends, Shift+Enter adds a newline | +| Stop a turn that is heading the wrong way | Press the square in the send disc. The session reads **Stopped** and offers **Continue** | +| Skip the install next time | Save the environment as an image from the session's **Runtime** tab | +| Work from a terminal | Install the Cortex CLI and drive the same sessions from there; see [Code in the terminal](/code/cli) | + +<Note> +**This PC** and **SSH** are not browser options. To run a session against a folder on your own machine or a registered remote host, use the Cortex desktop app or the Cortex CLI. +</Note> ## Related -- [Sessions](/code/sessions) · [Ask, Plan, Agent](/code/interactions) · [Cloud runtimes](/code/cloud) -- [Troubleshooting](/code/troubleshooting) +- [Code sessions](/code/sessions) for the board, the transcript and follow-ups. +- [Ask, Plan, Agent](/code/interactions) for what each mode may reach. +- [Permissions and approvals](/code/approvals) for both gates in full. +- [Changes and diffs](/code/changes) for reading a proposed diff. +- [Code troubleshooting](/code/troubleshooting) when a session will not start. diff --git a/code/repositories.mdx b/code/repositories.mdx new file mode 100644 index 0000000..2f27bc1 --- /dev/null +++ b/code/repositories.mdx @@ -0,0 +1,79 @@ +--- +title: "Repositories and branches" +description: "Choose the repository and base branch a Code session works on, and understand the isolated worktree and the branches a session may push." +icon: "code-branch" +--- + +Every Cortex Code session works on one repository, on one base branch, inside its own isolated worktree. You choose both before the first turn, with the two chips above the prompt box, and the choice stays with the session for its lifetime. + +There is no Repositories screen in Code to visit. The controls described here live in the composer, in the session's own panes, and on the **Environments** page, so this page is a map of where each choice is made rather than a tour of a settings screen. + +## Choose a repository and a branch + +The composer carries two context chips above the prompt. + +| Chip | Label | What it does | +| --- | --- | --- | +| First | **Choose a repository** | picks the repository the session works on. With no GitHub connection it offers **Connect GitHub** instead of an empty list | +| Second | **Branch** | picks the base branch. Leave it alone and the session uses the repository's own default branch | + +Both are set before you press **Start session**. If the repository list is not what you expect, the reason is almost always the connection rather than the picker, so start at [Connect GitHub](/code/github). + +## One repository per runtime + +A session works one repository at a time, and **a second repository means a second session**. This is the most repeated rule in Code and it is not a limitation to work around: it is why a session's changes stay legible, why its diff is readable, and why a runtime can be prepared from one repository up front. + +If a change spans two repositories, open two sessions and review two pull requests. + +## Your session's own worktree + +Each Cloud session works in **its own isolated worktree**, shown on the session's meta line as **worktree** followed by a name in the `cortex/` namespace. The worktree strip in the output pane states the rule in its own words: **Each Cloud session uses its own isolated worktree. Chat and the CLI are not this page.** Two sessions on the same repository therefore do not collide, and neither of them is working in whatever you happen to have checked out locally. + +The strip's **New worktree** action starts a fresh one, showing **Opening…** while it does. + +<Note> +**Pushes are limited to Cortex-owned branches.** The agent cannot push over your default branch. What arrives for review is a branch Cortex created and, once it exists, a pull request from it. +</Note> + +## Follow the branch through the session + +The **Git** tab in the output pane is where a session's branch and pull request show up, and it has an honest empty state for each stage: + +- **No branch yet** while nothing has been created. +- **No pull request** once a branch exists but no pull request has been opened. +- **Open pull request** once there is one to open. + +Changes reach that branch only after a person approves them. Until then each touched file sits in the **Changes** pane as a pending write, and you are reading a proposed diff rather than something that has landed. Because there is no undo, no checkpoint and no revert in Code, a pending change is the moment to use **Reject**. See [Changes and diffs](/code/changes) and [Permissions and approvals](/code/approvals). + +## A repository on the Environments page + +An environment is a machine of its own, built from a repository. Under **START ONE** on the **Environments** page the two fields are the same choice in a different shape: + +| Field | What it accepts | +| --- | --- | +| **Repository** | **A clone URL, or owner/name for GitHub.** | +| **Ref** | **Empty uses the repository default.** | + +A saved image is keyed by **repository and ref** together. The next session on that same pair resumes from the image instead of installing everything again, which is the single biggest difference between your first session on a repository and your tenth. See [Environments and images](/code/environments). + +## When the repository list is empty + +The empty copy tells you which of the three situations you are in. + +| What the list says | What it means | +| --- | --- | +| **Connect GitHub and your repositories appear here.** | there is no connection yet, so there is nothing to list | +| **GitHub returned no repositories for this account.** | the connection works, and it covers no repository Cortex can see. Widen it on GitHub's side | +| **No repositories to show yet.** | GitHub is not available to connect on this deployment | + +## What is not configurable + +There is no per-repository settings screen in Code, no default-repository setting, and no setting for a base branch or a branch prefix. Code settings store model defaults and nothing else, and the settings page says as much itself under **NOT CONFIGURABLE YET**: pull-request behaviour, a branch prefix, a network allowlist and a shell-command policy are all decided per session today. Every repository and branch choice is made when you start a session, or on the turn you send. See [Code settings](/code/settings). + +## Related + +- [Connect GitHub](/code/github) for the connection that fills the repository list. +- [Changes and diffs](/code/changes) for the gate a write passes before it reaches the branch. +- [Environments and images](/code/environments) for a machine prepared per repository and ref. +- [Code sessions](/code/sessions) for the session the repository belongs to. +- [Cloud runtimes](/code/runtimes) for the guest a session works inside. diff --git a/code/runtimes.mdx b/code/runtimes.mdx new file mode 100644 index 0000000..9a4ab73 --- /dev/null +++ b/code/runtimes.mdx @@ -0,0 +1,107 @@ +--- +title: "Cloud runtimes" +description: "What a browser Code session runs in: an isolated Cloud guest, how it starts and hibernates, and what happens when there is no capacity." +icon: "cloud" +--- + +Every Cortex Code session you start in the browser runs in its own **isolated Cloud guest**: a machine of its own, prepared from the repository you chose. Reads, searches, edits and shell commands all execute inside it. Nothing runs in your browser, and no other session or account shares that guest with you. + +This page explains what a Cloud runtime is, how one starts and goes to sleep, how to give a session a machine that already has your toolchain installed, and how Cortex behaves when a guest cannot be placed at all. There is no Runtimes screen in the product: the controls live in a session's **Runtime** tab and on the [Environments](/code/environments) page. + +## What a Cloud guest is + +- **It is prepared from your repository.** The first turn of a session attaches a guest and clones the repository you picked in the composer. That is why the first session on a new repository spends time installing before any work appears. +- **It is headless.** There is no screen, no desktop and no remote-desktop view in a Code runtime. A session's **Desktop** tab exists only with the badge **Soon**. If you want an agent with a screen and a browser, that is a Cortex Bot computer, not a Code runtime. +- **One repository per runtime.** A session works one repository at a time. A second repository means a second session. +- **It is where the diff comes from.** The **Diff** tab reads the guest's working tree live and captions it **Live from the Cloud guest**. When the tree cannot be read the pane says **The changes could not be read from the runtime.** rather than showing you an empty diff. +- **It holds no secrets.** Code has no Secrets page on any surface, and nothing in Code asks you to paste a token. + +Three different Cortex machines are easy to confuse. They are not interchangeable: + +| Surface | Machine | Screen | What it can reach | +| --- | --- | --- | --- | +| **Cortex Code** | an isolated Cloud guest | no, headless | the clone of your repository inside that guest | +| **Cortex Chat** | a small snippet sandbox | no | the snippet only, never a Code repository | +| **Cortex Bot** | an isolated Cloud guest | yes | the bot's own files and its browser | + +## The life of a guest + +| Event | What happens | +| --- | --- | +| The first turn needs it | The guest starts, attaches, and installs what the repository declares | +| You press **Stop** | The turn cancels. The guest and its files stay, and the session reads **Stopped** with a **Continue** button | +| The session sits idle | The guest may hibernate | +| You send a follow-up later | The guest is woken before the agent is prompted, which is why that turn starts slowly | +| You come back another day | The session resumes on its guest with the repository as you left it | + +While the runtime is being attached the session status reads **Connecting**, then **Connected**. The **Terminal** tab tells you where commands went: **Commands from this session run inside the Cloud guest.** + +A long-running command eventually times out rather than hanging the turn forever, and a whole turn has a wall-clock ceiling. Neither is a fault in your repository: read the transcript, narrow the command, and send it again. + +## Give a session its own machine + +A plain Cloud session installs what the repository declares every time. An **environment** is a machine you keep: Cortex clones the repository into it, the harness installs the toolchain, and you save the result as an image so the next session skips the install. + +<Steps> + <Step title="Open the Runtime tab"> + In an open session, choose **Runtime** in the output pane. While it looks for a machine it says **Looking for an environment…** With no repository on the session it says **No repository chosen**, because an environment is built from a repository. + </Step> + <Step title="Start one"> + Press **Give this session its own machine**, then **Start an environment**. + </Step> + <Step title="Install it"> + Press **Install the environment** and watch **Install progress** under **HARNESS**. It opens with **Cloning the repository and reading what it declares…** When nothing is reported yet the panel says **No progress was reported.** + </Step> + <Step title="Read the outcome"> + On success the section reads **ENVIRONMENT** with a **Verified with** line. On failure it reads **SETUP DID NOT FINISH** and offers the **Harness transcript** plus **Re-run setup**. + </Step> + <Step title="Save it"> + Press **Save image**. The toast confirms **Environment saved** and explains what you bought: **The next session on this repository and ref resumes from it.** + </Step> +</Steps> + +Each account can keep **8** registered environments and **40** saved images. Those are the only numbers worth planning around. Managing them is covered on [Environments and images](/code/environments). + +## What a runtime does not give you + +<Warning> +**There is no undo, no checkpoint and no revert.** A guest is not a save state you can roll back to. A file write is either rejected while it is still pending, or it lands. Plan on reviewing writes before they are applied, not on reversing them afterwards. See [Changes and diffs](/code/changes). +</Warning> + +- **You cannot scope a runtime by directory or by command.** There is no command allowlist and no per-directory allowlist anywhere in Cortex Code. The shell is allowed or withheld as a whole, per command, at the moment it is asked. What that decision looks like is on [Permissions and approvals](/code/approvals). +- **A file write is not approved on the permission rail.** Commands are answered with **Allow once**, **Always allow** or **Deny**; writes wait in **Changes** for **Approve**. Keep the two apart. +- **A Code session has no MCP servers, no connected apps and no plugins**, whatever runtime it is on. The session's **Tools** tab says so in its own words: **Off · this session has no MCP access.** and **Off · Chat and Bot access does not carry into Code.** Servers you add under [Code integrations](/code/integrations) are configured for the workspace, and a Code session may report no access to them. +- **There is no offline or mock Code runtime.** A deployment without a runtime fleet cannot run one at all, so there is nothing to try Code runtimes against. + +## When a runtime is not available + +Cortex fails closed here. If a guest cannot be placed, nothing is started, so nothing is lost. The surface separates three situations, and the right response differs for each: + +| What you see | What it means | What to do | +| --- | --- | --- | +| **Sign in to use an isolated environment** | An environment outlives the browser session that started it, so a guest could never come back to find or delete one | **Sign in** | +| **Isolated environments are not enabled here** and **This deployment has no runtime fleet. Cloud sessions still run.** | The capability is not enabled on this deployment | Nothing to do here, and this is not an upgrade prompt | +| **No environment capacity is available: the fleet is scaled to zero. Nothing was started, so nothing was lost.** | Capacity is momentarily at zero | **Try again** | + +A session never quietly relocates. A runtime is bound once per turn with no fallback, so an unusable runtime refuses the turn and names an action to take. + +The error codes you may meet: + +| Code | What happened | +| --- | --- | +| [`no_capacity`](/problems/no_capacity) | No guest could be placed right now | +| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Too many sessions active at once | +| [`service_unavailable`](/problems/service_unavailable) | The fleet is not answering | +| [`quota_exceeded`](/problems/quota_exceeded) | An environment or saved-image ceiling was reached | + +## Runtimes other than Cloud + +In the browser, **Cloud** is the runtime, plus a registered team runner when the deployment has one. Two more runtime kinds exist in the Cortex desktop app and the Cortex CLI: **This PC**, a machine you paired, and **SSH**, a registered remote host. See [Code on desktop](/code/desktop), [SSH hosts](/code/ssh-hosts) and [Machines](/code/machines). + +## Related + +- [Environments and images](/code/environments) - keep an installed machine and reuse it. +- [Machines](/code/machines) - Cloud occupancy and team runners. +- [SSH hosts](/code/ssh-hosts) - the third runtime kind, registered in the desktop app. +- [How Code works](/code/how-it-works) - the turn loop that runs inside the guest. +- [Code troubleshooting](/code/troubleshooting) - failed starts and capacity problems. diff --git a/code/security.mdx b/code/security.mdx index 4fe509a..f7f5463 100644 --- a/code/security.mdx +++ b/code/security.mdx @@ -1,59 +1,85 @@ --- -title: "Cortex Security" -description: "GitHub pull-request review without pasting a diff. Cortex reads the change in place and posts a check run that stays failed when it fails." -keywords: ["pull request review", "check run", "GitHub App"] +title: "Pull-request review" +description: "Cortex Security reads a pull request instead of writing one. Where it sits inside Code, how to reach it, and which tab documents it." +icon: "shield-halved" --- -Cortex Security reviews GitHub pull requests in place. Install its GitHub App from the product, and each pull request gets one review pass posted as a check run named **Cortex Security**. A review that could not run is stored as failed — never rewritten as an approval so a dashboard can look green. +Two parts of Cortex touch your repository, and they do opposite things. A **Cortex Code** session writes code: it edits files, runs commands, pushes a Cortex-owned branch and opens a pull request. **Cortex Security** reads a pull request: it reviews the change where it already is and posts its findings back onto GitHub, and it changes nothing in your tree. Security is part of Code rather than a separate application, which is why you reach it from inside the Code area and sign in once for both. -<Frame caption="cortex.foundation/security — the public product page. The signed-in inbox is /code/security in the app."> - <img src="/images/product/security-public.png" alt="Cortex Security public page — GitHub pull-request review without pasting a diff" /> -</Frame> +This page exists so those two are never confused. It covers the boundary between them, how you get from a Code surface to Security, the three separate GitHub installs that the word "connect" can mean, and what a review deliberately will not do. Everything about how a review actually works, what a check run says and how the policy is set, is documented in the [Cortex Security](/security/index) tab. -## Two routes, two things +## Writing a change, reviewing a change -| Route | What it is | -| --- | --- | -| `cortex.foundation/security` | The public **product page** for Cortex Security | -| `/code/security` in the app | The signed-in **review inbox** | -| [Security and privacy](/security/overview) on this site | How Cortex handles your data — a different subject | +| | A Code session | A Security review | +| --- | --- | --- | +| What it does | Edits files and runs commands inside an attached runtime | Reads a pull request in the repository | +| What it produces | A branch and a pull request | Inline comments, a summary comment and a check run | +| What it changes in the repository | The branch it owns, once you have approved the writes | Nothing | +| Who starts it | You, from the composer | A pull request being opened or updated | +| Where you watch it | The session transcript, **Changes**, the **Git** tab | The pull request itself, and the review inbox | -## Install and review +The practical version: if you want something built or fixed, start a Code session. If you want a second pair of eyes on a change someone has already proposed, that is a review, and you do not start it from a session. -<Steps> - <Step title="Sign in and open /code/security"> - Choose **Code** in the product switcher, then **Security**. - </Step> - <Step title="Install the Cortex Security GitHub App"> - From the inbox, install the app on the repositories you want reviewed. This is a separate install from [Connect GitHub](/code/github), which is for Code sessions. - </Step> - <Step title="Open a pull request"> - Cortex reads the diff in place and posts a check run named **Cortex Security** with its findings. - </Step> - <Step title="Read the inbox"> - Every review lands in `/code/security` with the status the pass earned. - </Step> -</Steps> +## Reaching Security from Code -<Frame caption="The product's four commitments: the pull request is the input, a failed review stays failed, same account and domain, built for the review rather than the paste."> - <img src="/images/product/security-public-features.png" alt="Cortex Security feature grid — The pull request is the input, A failed review stays failed, Same account same domain, Built for the review not the paste" /> -</Frame> +Security appears on several Code surfaces, and in each case it is a link rather than a setting. -## How a review behaves +- **The composer's fourth row, Security.** Under **Ask**, **Plan** and **Agent** there is a row labelled **Security**, with the hint **Open Security mode for this repository**. It is not a fourth interaction mode. Pressing it leaves the composer for Cortex Security and the session's own interaction stays Ask, Plan or Agent. See [Ask, Plan, Agent](/code/interactions). +- **The quick action on Code Home, Run a security audit.** The two quick actions beside it write text into the prompt box. This one navigates away, which is why it carries an outward arrow. +- **The badge Security mode is on.** Home shows it when Security is active for the repository in front of you. +- **The command palette.** Its navigate group has a **Security** row alongside Home, Sessions, Environments, Automations, Usage and Notifications. +- **An old bookmark.** A `/code/review` link still lands on Security, so a saved link from before the move keeps working. -| Behaviour | Why | -| --- | --- | -| One pass over the diff | A review is a pass, not a conversation | -| Failed stays failed | A review that could not run is stored as failed, never as approved | -| Nothing is pasted | Pasting a patch into an assistant is how secrets and context leak. This surface has no such box. | -| Policy is fixed by the repository owner | Policy lives at `/code/security/policy` in the app. A pull request cannot reduce the scrutiny it receives. | +## Three different GitHub installs -## Cortex Security and the CLI +This is where the confusion usually happens. Three separate things install against GitHub, and having one of them gives you none of the others. -The CLI can run a review in CI from the working tree — `cortex exec --auto read-only --git-diff "review this diff"` — and `cortex github install` scaffolds the workflow. That is a headless Code run, not the Cortex Security GitHub App; use whichever fits your pipeline, or both. See [Headless runs](/cli/headless). +| Install | What it is for | Where it is documented | +| --- | --- | --- | +| **Connect GitHub** | Lets Code list your repositories, prepare a runtime from one and open a pull request | [Connect GitHub](/code/github) | +| The **Cortex Security GitHub App** | Lets Security read pull requests and post its checks and comments | [Installation and repositories](/security/repositories) | +| The Cortex CLI's own install command | Wires the CLI to GitHub for terminal runs | [Cortex CLI](/cli/index) | + +So a repository that Code can open a pull request against is not automatically a repository Security reviews, and installing the Security App does not give a Code session anything it did not have. + +## What a review will not do + +- **A failing review stays failed.** The result is stored with the status the pass earned. It is not softened into a warning or rewritten as an approval so that a dashboard can look finished. +- **Nothing is pasted.** There is no box anywhere in Security for pasting a patch. The change stays in the repository and Cortex reads it there, which is also why an older paste-a-diff review view was retired. +- **A review does not write your tree.** Even when a finding arrives with a suggested change, applying it stays a human decision on GitHub. A session opened from a finding says so in its own words: **The finding is on this branch. Approve in GitHub to apply it — Cortex never writes the tree from a finding.** +- **A pull request cannot lower its own scrutiny.** The review policy belongs to the installation and has its own screen in the app, described in [Review policy](/security/review-policy). + +<Note> +Whether a failing check blocks a merge is GitHub's decision, not Cortex's. It depends on whether you have made the check a required one in your branch protection settings. See [Checks and comments](/security/checks). +</Note> + +## What the Security tab documents + +<CardGroup cols={2}> + <Card title="Cortex Security" icon="shield-halved" href="/security/index"> + The map of the tab: what the product guarantees and where each page goes. + </Card> + <Card title="Security quickstart" icon="rocket" href="/security/quickstart"> + Install the GitHub App, enable a repository, read a first review end to end. + </Card> + <Card title="How a review works" icon="diagram-project" href="/security/how-a-review-works"> + The stages a review moves through, and how a verdict is reached. + </Card> + <Card title="Checks and comments" icon="circle-check" href="/security/checks"> + The check run, the summary comment, inline findings, and asking for another pass. + </Card> + <Card title="Repository scans" icon="magnifying-glass" href="/security/scans"> + Scanning a repository you own, rather than reviewing one pull request. + </Card> + <Card title="Cortex Agent runs" icon="robot" href="/security/agent"> + Evidence gathered by running a change, and why a run is never a pass on its own. + </Card> +</CardGroup> ## Related -- [Connect GitHub](/code/github) — the other GitHub install. -- [Security and privacy](/security/overview) — data handling and sandboxes. -- [Troubleshooting](/code/troubleshooting) — what a failed check run means. +- [Cortex Security](/security/index) for the product in full, in its own tab. +- [Connect GitHub](/code/github) for the connection Code sessions use. +- [Ask, Plan, Agent](/code/interactions) for why **Security** is not a fourth mode. +- [Automations](/code/automations) for a saved Code prompt, which is not a review either. +- [Security troubleshooting](/security/troubleshooting) when a review does not appear. diff --git a/code/sessions.mdx b/code/sessions.mdx index 655bb0b..f80383f 100644 --- a/code/sessions.mdx +++ b/code/sessions.mdx @@ -1,69 +1,109 @@ --- title: "Code sessions" -sidebarTitle: "Sessions" -description: "A Code session is a timeline of the task you asked for and the work that followed — files read, edits, commands, plans — not a chat transcript." -keywords: ["timeline", "task", "transcript", "run"] +description: "What a Code session is, how to find and read one, follow-ups, attach and detach, stopping a turn, and what survives when it ends." +icon: "list-check" --- -A session is where Code does its work on one repository. It records every turn as a timeline: what you asked, which files the agent read, what it edited, which commands it ran, and the plan it wrote when you asked for one. You can stop a turn at any point and follow up with another. +A session is where Cortex Code does its work on one repository. It records what you asked, the files the agent read, the edits it proposed, the commands it ran and the plan it wrote when you asked for one. It is a timeline of work rather than a chat transcript, and it stays on your account so you can come back to it. -## Anatomy of a session +This page covers the session as an object: how it is named, how to find one again on the sessions board, how to read the transcript and the output pane, how follow-ups and queueing work, what attaching and detaching mean, and what is still there when the turn is over. -| Part | What it shows | -| --- | --- | -| **Header** | Repository, host (Cloud in the web app), run state, and **Stop** | -| **Turns** | Your request, then the work: reads, edits with diffs, commands with output, plan blocks | -| **Mode** | Ask, Plan, or Agent on each turn; the session row holds the default. See [Ask, Plan, Agent](/code/interactions) | -| **Composer** | Where the next turn starts | +## What a session is + +- **One repository, one session.** A session works a single repository at a time. A second repository means a second session. +- **Its own isolated worktree.** Each Cloud session gets one, shown on the meta line as **worktree** and the branch name. **New worktree** starts a fresh one. +- **Its title is your prompt.** The first line of what you typed becomes the session title, and a very long line is shortened. You can rename it: hover the title, press the pencil, and the popover saves with **Title saved** or reports **The title could not be saved**. A renamed session updates in the sidebar list too. +- **Untitled until it has one.** A session with no usable title reads **Untitled session**. +- **One model, pinned.** The model is chosen in the composer before you start and shown on the session row and the meta line. What it starts on comes from **Default model** in [Code settings](/code/settings), which a workspace can leave on **Server default**. +- **Cost only when there is cost.** The row shows a spend figure only when the session has a recorded spend, so most rows do not carry one. See [Usage](/code/usage). +- **Where it came from.** A session started from a terminal is marked **· Started from CLI** on the board. See [Code in the terminal](/code/cli). + +## Find a session again -In the CLI the same session appears as a terminal timeline with tool rows — the tool name, a short argument summary, and the result indented beneath it. See [The TUI](/cli/tui). +**Sessions** is the board of everything on your account. Its description line counts the sessions, the repositories they span and how many are running right now. + +| Control | What it does | +| --- | --- | +| **Search** | matches the title, the repository or the branch, case-insensitively | +| **Status** | filters by **All**, **Running**, **Needs review** or **Failed** | +| **Repo** | filters to one of the repositories your sessions actually name | +| **Command palette** | opens the palette, also on Command+K or Ctrl+K | +| **New session** | goes back to the composer on Code Home | -## Start a session +Rows are grouped by **when, not where**: **Today**, **Yesterday**, **This week** and **Earlier**, each with a count. A session whose timestamp cannot be read lands in **Earlier** rather than disappearing from the board. -<Steps> - <Step title="Sign in and open Code"> - Exact `/code` is the public product page for a guest; the working UI is for members. - </Step> - <Step title="Connect GitHub if the work needs a repository"> - [Connect GitHub](/code/github) from Code Home, the repository picker, or **Settings → Integrations**. - </Step> - <Step title="Pick the repository"> - Cortex starts and attaches a Cloud guest for it, then prepares the environment. If no runtime is attached when the first command would run, the harness starts one — an unattached runtime is never the first step you see. - </Step> - <Step title="Describe the change and watch the timeline"> - Reads, edits, and commands appear as they happen. **Stop** cancels the live turn if it is heading the wrong way. - </Step> -</Steps> +**Needs review** deliberately covers two different waits: a pull request waiting on a human, and a permission prompt waiting on a decision. Both are the same request of you. -## Follow-ups +The whole row is the link. There is no card and no separate open button: the title line sits above a line reading the state, the model, the repository and how long ago it ran. When you have no sessions at all the board offers **Start your first session**. -A session is a conversation with a repository, so follow-ups carry context: *now add the test*, *undo the last change*, *explain why you chose that library*. Each follow-up can pick a different mode. +## Read a session -## Stop and cancel +The header carries **Back to sessions**, the title with its rename pencil, the repository and base branch, the session cost, the view controls and the run state, with a small green dot while a turn is running. Nothing else: stopping is done in the composer, and the pull request lives on the **Git** tab. The meta line under it names the model, when it last ran, the runtime and the worktree branch. -**Stop** in the header cancels the live turn. The timeline records that the turn stopped; the work already written to the repository stays, so read the diff before your next turn. In the CLI, **Esc** interrupts and the timeline shows `× Stopped`. +The transcript is labelled **Session transcript**. Your ask is drawn as the **Task** line, and the work follows as **Read**, **Edited**, **Ran** and **Worked** rows with durations, plus **Thought** rows where the agent reasoned. A finished row with a lot of output is folded: **Long finished results are folded. Press Ctrl+O to expand every row.** On a Mac, Ctrl+O and Command+O both expand, and expanding is one way; there is no chord to fold them back. Before anything has run the column reads **Nothing has run in this session yet. Describe a task below and Cortex will start work.** -## What is in the session and what is not +To the right, **Session output** carries the tabs. -| In the session | Not in the session | +| Tab | What is on it | | --- | --- | -| The repository, checked out in the guest | Your other repositories | -| Environment the agent installed for this repository | A shared Secrets page — there is none; environment belongs to the guest | -| Files, diffs, command output, plans | A Chat transcript or Chat's Python sandbox | -| The mode you chose per turn | A model picker — web Code has none | +| **Changes** | the files this session wants to write, and the **Approve** gate on them | +| **Diff** | the attached runtime's working tree, captioned **Live from the Cloud guest** | +| **Git** | **Open pull request**, or **No pull request** and **No branch yet** | +| **Terminal** | what ran, or **No commands have run in this session yet.** | +| **Plan** | present only when the session has a plan | +| **Runtime** | the environment panel for this session | +| **Tools** | the tool servers this session can reach, which for a Code session is none | +| **Desktop** | drawn with the badge **Soon**; it does not exist yet | + +See [Changes and diffs](/code/changes) for the two panes that matter most. + +## Send a follow-up + +The follow-up box floats at the bottom of the transcript, labelled **Follow-up**, with the placeholder **Ask a follow-up or adjust the plan…** Enter sends and Shift+Enter inserts a newline. It carries the same mode menu as the composer, so **Ask**, **Plan** and **Agent** can change on every turn, and the new mode applies to the turn you are sending rather than to one already running. + +Sending while a turn is running does not interrupt it. The follow-up becomes a **Queued follow-up** and waits. Press **Reclaim**, or Escape, or ArrowUp in an empty box, to take the text back into the composer. Only the session's owner can do that: **Only the owner can return this follow-up.** -## Web, desktop, CLI +Two commands are understood in that box, both with the leading slash: `/btw` opens **Ask on the side**, a scratch pad that runs no tools and settles no approvals, and `/compact` compacts the session, keeping any text you put after it in focus. Anything else is sent as a normal turn. -| Surface | Host options | Session storage | +## Attach, detach and the side views + +**Detach** stops you watching. It does not stop the turn: the hint says **You are watching this session. Detach does not stop the turn. Attach again to send or to Allow or Deny.** A detached viewer cannot send a follow-up and cannot answer a decision, so **Attach** again first. + +The header's views change what you see, not where the session runs. **Focus** narrows the page, and **Exit Focus** leaves it; approvals still interrupt you there. **Open Updates** lists the named progress this session reported, newest first, with tool arguments left off the list. **Tower** is available when you are signed in and needs an isolated guest; it keeps shipping behind a reviewed pull request. + +## Stop, continue, try again + +While a turn runs, the send disc is a square. Press it to stop. The cancel is recorded once, so pressing it again does nothing extra, and the session then reads **Stopped** with a **Continue** button that sends **Continue from where you stopped.** + +A turn that ended in error is a different state: **Failed**, with **Try again**. A cancelled session is never shown as failed. + +| Status | What it means | What you do | | --- | --- | --- | -| Web app | Cloud | On your account | -| Desktop app | Cloud, This PC, SSH | On your account | -| CLI | Cloud by default, This PC / SSH by opt-in | On your account, plus a local transcript you can resume, export, and share. See [CLI sessions](/cli/sessions) | +| **Running** | a turn is in flight | watch it, or stop it | +| **Waiting for approval** | a prompt or a pending write is blocking | answer it | +| **Needs review** | a pull request or a decision is waiting on a human | review it | +| **Completed** | the turn finished | read the diff, open the pull request | +| **Failed** | the turn ended in error | **Try again** | +| **Interrupted** | the turn was cut short | send a follow-up | +| **Stopped** | you cancelled it | **Continue** | +| **Ready** | idle and usable | send a turn | +| **Connecting** | the runtime is being attached | wait | +| **Connected** | the runtime is attached | carry on | + +A session bound to a machine you paired yourself can also report that its host is not there, and the follow-up box says what to do: **This session runs on This PC, and no host is connected. Pair one from the Host pane and the composer comes back.** That path lives in the desktop app; see [Code on desktop](/code/desktop). + +## What survives a session + +When the turn is over, the session keeps its row and title, its full transcript, its plan, its worktree branch, its pull-request link and its recorded usage. Approved writes live in the branch, where the pull request is the record of them. -The CLI reuses the same Code session id for a workspace, so turns from the terminal continue the same coding session. +<Warning> +There is no undo, no checkpoint and no revert of a turn's edits, in this session or any other. Rejecting a write while it is still pending in **Changes** is the only way to refuse it from inside Cortex. +</Warning> ## Related -- [Ask, Plan, Agent](/code/interactions) — what each mode may do. -- [Cloud runtimes](/code/cloud) — the guest behind the session. -- [How Code works](/code/how-it-works) — the workspace tool catalog. +- [Ask, Plan, Agent](/code/interactions) for what each mode may reach. +- [Permissions and approvals](/code/approvals) for the prompt card and the write gate. +- [Changes and diffs](/code/changes) for reading and approving a diff. +- [How Code works](/code/how-it-works) for the loop behind the transcript. +- [Code troubleshooting](/code/troubleshooting) when a session will not open. diff --git a/code/settings.mdx b/code/settings.mdx new file mode 100644 index 0000000..91a4a83 --- /dev/null +++ b/code/settings.mdx @@ -0,0 +1,72 @@ +--- +title: "Code settings" +sidebarTitle: "Settings" +description: "Code settings holds model defaults for your workspace. Everything else about a session is chosen when you start it, not saved here." +icon: "gear" +--- + +**Code settings** is a short page, and knowing why it is short will save you a hunt. It holds the defaults Cortex Code applies to new sessions in your workspace, described on the page as **Defaults for sessions in this workspace.** In practice that means model defaults, plus pointers to the three places where the rest of Code's configuration actually lives. + +This page covers the fields you can set, what each one does, and the larger set of things a reader expects to find here and will not. Cortex is explicit about that second group rather than drawing controls that would quietly forget what you set. + +## Model defaults + +The **MODEL DEFAULTS** section is the only part of the page that saves anything. + +| Field | What it does | +| --- | --- | +| **Default model** | The model new sessions start on. Leave it on **Server default** to let Cortex choose, which is what a fresh workspace does. | +| **Fallback models** | **Comma-separated slugs, tried in order when the default is unavailable.** | + +Two things are worth being precise about. **Server default** is not a model name, it is the absence of a choice: it leaves the field unset and lets the deployment decide. And fallbacks are tried **in order**, so put the model you would actually want second in second place. + +<Note> +Every field here is a **workspace default**. Nothing on this page is per session, per repository or per runtime. A default changes what a new session starts with; it does not reach into a session that already exists, and a session can always be started on a different model from the composer's model chip. +</Note> + +## What is chosen per session, not here + +Two things readers most often come looking for are genuinely not settings. + +**The interaction mode is not saved.** **Ask**, **Plan** and **Agent** are chosen in the composer when you start a session, and again on each follow-up. The mode is a lock on the set of tools a turn is built with, not an instruction the model is asked to follow, and because the set is chosen when the turn is built, a change applies to the **next** turn rather than to one already running. A new session defaults to **Agent**. See [Ask, Plan, Agent](/code/interactions). + +**The runtime is not saved either.** It is chosen at the moment the session starts. In the browser, sessions run on Cloud, which is what the page's own pointer says. See [Cloud runtimes](/code/runtimes). + +## Approvals are per session, in two separate places + +There is no workspace policy for what a session may do. Instead a session asks, and it asks in two different places that are easy to conflate. + +- **Commands** raise a card above the transcript with **Allow once**, **Always allow** and **Deny**. **Always allow** is a grant for the rest of **that session** only. It is not an account setting, and it does not carry to another session, to Cortex Chat or to the Cortex CLI. See [Permissions and approvals](/code/approvals). +- **File writes** never appear on that rail. They collect in the session's **Changes** pane as pending files, and a human presses **Approve**, **Approve all** or **Reject**. A session-level **Always allow** never covers a write. See [Changes and diffs](/code/changes). + +<Warning> +There is no setting, here or anywhere, that scopes which commands a session may run or which directories it may touch, and there is no undo, no checkpoint and no revert of a turn's edits. The review point is the approval itself: read the pending diff in **Changes** before you approve it, because approving is what puts it in the tree. +</Warning> + +## Not configurable yet + +The page carries its own paragraph about the missing controls, and it is the most useful sentence on the screen: + +> **Pull-request behaviour, a branch prefix, a network allowlist and a shell-command policy are all decided per session today: a session asks before it runs a command, and you allow, always-allow or deny it. There is no workspace-level field for any of them, so there is no control here that would forget what you set.** + +The same applies to a default repository, a pull-request destination, a base branch and migration approval. None of them is a saved setting today, so do not plan a team convention around one. If you need a branch convention or a pull-request rule enforced, enforce it in the repository or at review time, not from this page. See [Repositories and branches](/code/repositories). + +## Where the rest lives + +The **ELSEWHERE** section is three pointers, with the page's own descriptions: + +- **Integrations and MCP servers**, covered in [Code integrations](/code/integrations). +- **Cloud runtimes**, with the note **Sessions in the browser run on Cloud.** +- **Notifications**, described as **What Cortex tells you about, and what it has already told you.** + +<Info> +Where the workspace boundary sits on a team account, and who on a team may change these defaults, is not documented. If you share an account, agree on the defaults before you change them. +</Info> + +## Related + +- [Code integrations](/code/integrations) +- [Ask, Plan, Agent](/code/interactions) +- [Permissions and approvals](/code/approvals) +- [Cloud runtimes](/code/runtimes) +- [Code notifications](/code/notifications) diff --git a/code/ssh-hosts.mdx b/code/ssh-hosts.mdx new file mode 100644 index 0000000..97c673d --- /dev/null +++ b/code/ssh-hosts.mdx @@ -0,0 +1,80 @@ +--- +title: "SSH hosts" +description: "SSH is one of three runtime kinds a Code session can bind. Hosts are registered in the Cortex desktop app, and keys never reach your browser." +icon: "server" +--- + +A Cortex Code session runs in one of three kinds of place: **Cloud**, an isolated guest Cortex prepares for you; **This PC**, a machine you paired with the Cortex desktop app; or **SSH**, a registered remote host. This page is about the third one. + +Two things to settle before anything else. There is **no SSH hosts page in the browser**: the registration screen belongs to the Cortex desktop app, where it is labelled **Connect a server**. And the browser offers **Cloud** only, plus a registered team runner when the deployment has one, so nothing on this page changes how a session you start in a browser tab behaves. + +## Where SSH fits + +| Surface | Runtimes it offers | +| --- | --- | +| Browser | **Cloud** only, plus a registered team runner when the deployment has one | +| Cortex desktop app | Cloud, **This PC**, **SSH** | +| Cortex CLI | Cloud by default; This PC and SSH by opt-in | + +A session binds one runtime, **once per turn**, and there is no fallback. If the host you chose is not usable, the turn refuses and names an action to take. It does not quietly run your repository in the cloud instead, which is the behaviour you want from something that was supposed to touch a particular machine. + +In the desktop app's runtime picker, the **SSH** row carries its own one-line description: **A registered remote host. Tools run on that machine.** With nothing registered, the picker tells you so rather than showing an empty list: **No SSH hosts are registered yet.** + +## Register a host + +Registration happens in the Cortex desktop app, on the screen labelled **Connect a server**. You can also reach it from the command palette, where **Connect a server** is one of the listed actions. See [Code on desktop](/code/desktop) for the app's own layout and where its settings live. + +<Warning> +**Keys stay server-side.** The browser never receives SSH keys or host keys. That is the whole of what Cortex documents about key handling, and it is deliberate: there is no place in Code to paste a key, and no page that will show one back to you. +</Warning> + +Related to that: **Code stores no secrets.** There is no Secrets page on any Code surface, and nothing in Code asks you for a token to paste. Whatever a run needs, the agent arranges inside the runtime for that run. + +## Choose SSH for a session + +<Steps> + <Step title="Open the Cortex desktop app"> + A browser tab cannot do this. **This PC** and **SSH** are desktop and CLI vocabulary, and the browser never offers either. + </Step> + <Step title="Pick SSH on Code Home"> + Choose **SSH**, then **Choose an SSH host** and pick one you have registered. + </Step> + <Step title="Describe the task and start"> + The rest of the session behaves as it does everywhere else: the same **Ask**, **Plan** and **Agent** modes, the same permission prompts, the same **Changes** gate on file writes. + </Step> +</Steps> + +From the Cortex CLI, the same choice is made with environment variables: `CORTEX_COMPUTER=ssh` selects the SSH runtime and `CORTEX_SSH_HOST` names the host. Unsetting `CORTEX_COMPUTER` returns you to Cloud. Both This PC and SSH require an already connected Code session. The commands themselves, and the rest of the CLI's host handling, are on [Code in the terminal](/code/cli) and [Hosts](/cli/hosts). + +## Treat SSH as a registration surface today + +<Note> +SSH is documented here as what it reliably is: a way to register a remote host in the Cortex desktop app and select it for a session. Cortex does not promise that a given turn will execute on that remote machine, and nothing on this page should be read as that promise. If you need a place where a turn is certain to run today, use **Cloud**, which is what the browser offers and what every surface falls back to by default. +</Note> + +If a host cannot be used, you will see the refusal rather than a silent relocation. In the desktop app, a host that could not be woken reports **The remote Code host did not come back.**, a host still being attached reports **Connecting to the Code host…**, and a session waiting on a decision takes precedence over both, because a run waiting on **Allow**, **Always** or **Deny** matters more than whether a machine's shell is up. + +When a session was bound to your own machine and no host is connected, the composer is disabled and says what to do: **This session runs on This PC, and no host is connected. Pair one from the Host pane and the composer comes back.** + +## Vocabularies that do not mix + +- **An SSH host is not This PC.** SSH chrome never uses the name **This PC**, and the two are separate runtime kinds with separate registration. +- **An SSH host is not a Cortex Bot host.** A bot's computer is a different machine for a different product, with a screen and a browser. A Code runtime is headless. +- **A team runner is not an SSH host.** Team runners are the only non-Cloud compute the browser knows about, and they are listed on [Machines](/code/machines). A paired or registered desktop host is never listed there. + +## What choosing a host does not change + +- **There is no command allowlist and no per-directory allowlist anywhere in Cortex Code.** You cannot register a host and then scope it to one folder or one set of commands. The shell is allowed or withheld as a whole, per command, at the moment it is asked. See [Permissions and approvals](/code/approvals). +- **A file write is approved under Changes**, not on the **Allow once** / **Always allow** / **Deny** rail. The two gates stay separate on every runtime. See [Changes and diffs](/code/changes). +- **There is no undo, no checkpoint and no revert.** A write on a remote host is either rejected while it is still pending, or it lands on that machine. Review before approving. +- **A Code session has no MCP servers, no connected apps and no plugins**, on a remote host as anywhere else. + +Some details about host registration are simply not documented: what the **Connect a server** screen asks for, how a host is verified, how many you may register, and whether a host can be shared with the rest of a workspace. If you need one of those answers, the desktop app is the place to look rather than a number quoted here. + +## Related + +- [Cloud runtimes](/code/runtimes) - the runtime the browser always has. +- [Code on desktop](/code/desktop) - where **Connect a server** and **This PC** live. +- [Machines](/code/machines) - Cloud occupancy and team runners, and why hosts are absent. +- [Code in the terminal](/code/cli) - selecting a runtime from the Cortex CLI. +- [Permissions and approvals](/code/approvals) - what a session asks before it runs a command. diff --git a/code/tickets.mdx b/code/tickets.mdx new file mode 100644 index 0000000..b84991b --- /dev/null +++ b/code/tickets.mdx @@ -0,0 +1,65 @@ +--- +title: "Tickets" +description: "A ticket is a unit of asynchronous work with a title, a body and a status. Tickets have no screen in Cortex Code yet." +icon: "ticket" +--- + +A ticket is Cortex Code's unit of asynchronous work: a small record with a title, a body and a status, which can point at the session that is doing the work. It exists so that a piece of work can outlive the turn that raised it, and so that a status can be tracked without keeping a transcript open. + +This page is deliberately short, because tickets are honest about what they are today. **There is no Tickets screen anywhere in Cortex Code**, in the browser, in the Cortex desktop app or in the Cortex CLI. What follows is what a ticket is made of, the statuses it can hold, and where to track work in the meantime. + +<Note> +Tickets are an API level concept today. Nothing in the app opens them, lists them or files them, so there is no page to go to, no sidebar entry and no inbox of tickets to read. See [Platform API](/reference/platform-api) for the surface they belong to. +</Note> + +## What a ticket holds + +| Field | What it is | +| --- | --- | +| Title | A short name for the work. | +| Body | The detail. A ticket body is stored sealed on the server. | +| Status | One of five values, listed below. | +| Session reference | Optional. The Code session working on the ticket, when there is one. | + +## The five statuses + +A ticket's status is one of exactly five values, lower-case on the wire: + +| Status | What it means | +| --- | --- | +| `open` | Raised, not started. | +| `in_progress` | Work is under way. | +| `blocked` | Work cannot continue until something else changes. | +| `done` | Finished. | +| `cancelled` | Abandoned on purpose, rather than finished or failed. | + +Any other value is refused as a validation failure rather than stored as an unknown state, so a ticket can never sit in a status nothing understands. See [validation_failed](/problems/validation_failed) for what that refusal looks like. + +## A ticket outlives the session it points at + +A ticket that references a session keeps existing when that session is deleted. The reference is cleared, and the ticket itself, with its title, body and status, stays exactly as it was. Deleting a session is not a way to close a ticket, and losing a session does not lose the record of the work. + +## What is not available yet + +<Warning> +Do not plan a workflow around tickets today. There is no screen that creates, lists, assigns or closes one, and a ticket does not start a Code session by itself. If you need work to happen, send a turn in a session. +</Warning> + +Also not documented, because no source establishes it: where a ticket will appear to you when a surface arrives, who will be able to raise one, whether raising one will ever start a session, and whether a ticket will produce a notification. + +## How to track work in Code today + +Until tickets have a surface, the things Cortex Code actually shows you are the honest place to track work: + +- **The sessions board.** Every session your account has run is listed and grouped by **Today**, **Yesterday**, **This week** and **Earlier**, with a **Status** filter offering **All**, **Running**, **Needs review** and **Failed**. **Needs review** is the one that means a human is holding something up, either a pull request waiting to be read or a decision waiting to be answered. See [Code sessions](/code/sessions). +- **Notifications.** The inbox tells you when a session finished, when it needs a decision, and when an automation ran, newest first. See [Code notifications](/code/notifications). +- **Automations.** A saved instruction keeps the text of a recurring job in one place, with a trigger and a repository, although nothing runs unattended yet: **Schedules and events do not execute yet.** See [Automations](/code/automations). +- **Pull requests.** A finished change lands as a branch and a pull request on the **Git** tab, which is where review and closure genuinely happen today. See [Changes and diffs](/code/changes). + +## Related + +- [Code sessions](/code/sessions) for the board, the filters and what survives a turn. +- [Code notifications](/code/notifications) for what Cortex tells you about. +- [Automations](/code/automations) for saved instructions and what a run does today. +- [Changes and diffs](/code/changes) for the branch and the pull request a session produces. +- [Platform API](/reference/platform-api) for the API surface tickets belong to. diff --git a/code/troubleshooting.mdx b/code/troubleshooting.mdx index d23917d..9d39669 100644 --- a/code/troubleshooting.mdx +++ b/code/troubleshooting.mdx @@ -1,70 +1,142 @@ --- title: "Code troubleshooting" -description: "Gates, Reconnect, Cloud availability, modes that will not edit, and what a failed Cortex Security review means." -keywords: ["errors", "problems", "fixes", "not working"] +description: "What Cortex Code tells you when something is wrong, what each message actually means, and which page owns the fix." +icon: "life-ring" --- -Code tells you what is wrong in plain words. This page maps those words to causes and fixes. For the terminal, see [CLI troubleshooting](/cli/troubleshooting); for the rest of the app, [Troubleshooting](/getting-started/troubleshooting). +Cortex Code says what is wrong in plain words rather than in codes, so most of the time the message on screen is the diagnosis. This page maps those messages to their real cause and points at the page that owns the fix. It is grouped the way the product is: access, GitHub, the runtime, turns that will not edit anything, session control, context, changes, automations, Cortex Security, and the error codes underneath all of it. + +Three questions answer a surprising number of problems before you read any further. Are you signed in, since a guest sees a reduced surface and cannot start work. Are you **attached** to the session, since a detached viewer can watch but cannot send or decide. And which mode did you send the turn in, since **Ask** and **Plan** are built without the tools that change files. For the terminal, see [CLI troubleshooting](/cli/troubleshooting); for the rest of the products, [Troubleshooting](/getting-started/troubleshooting). ## Access -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| **This space is reserved** | You are not signed in | **Sign in**, or **Continue in Chat** | -| The public product page at `/code` | Same — guests see the product page | Sign in, then choose **Code** | -| `/code/secrets` sends you home | There is no Secrets page | Set environment inside the session; see [Cloud runtimes](/code/cloud) | +| **This space is reserved**, with **Continue in Chat** and **Sign in** | you followed a link into Code while signed out | sign in, or take the work to Cortex Chat | +| The public product page where you expected the composer | guests get the product page at Code rather than the session composer | sign in, then open Code | +| A link to a secrets page sends you back to Code Home | there is no Secrets page in Code, on any surface | nothing to fix. Code stores no secrets and nothing in it asks you to paste a token | +| Pressing **Connect GitHub** takes you to sign-in instead of GitHub | holding a connection requires an account | sign in first, then connect | ## GitHub -| What you see | Cause | Fix | +| What you see | What it means | What to do | +| --- | --- | --- | +| No **Connect GitHub** control anywhere | GitHub is not available on this deployment | the control is absent rather than greyed out, and there is no token field to fall back on. Ask whoever runs the deployment | +| **Reconnect GitHub** | the connection lapsed or was revoked | press it and approve on GitHub again. Nothing was changed in the meantime | +| A repository you expect is missing from the picker | the grant on GitHub does not cover that repository | reconnect, and include it on GitHub's own consent screen | +| **GitHub did not complete the connection**, **GitHub took too long**, or **GitHub is not available to connect** | GitHub failed, did not answer in time, or is unreachable | try again. Each of these ends with nothing changed on your side | +| **This connection attempt is no longer valid** | the attempt went stale or had already been used | start again from **Connect GitHub** rather than reloading the old page | +| **GitHub was not connected** | you pressed **Cancel** on GitHub's consent screen | this is a decision, not a fault. Connect again whenever you want to | + +The full set of states and messages, and how to revoke the connection, is on [Connect GitHub](/code/github). + +## Runtime, environments and capacity + +| What you see | What it means | What to do | | --- | --- | --- | -| No **Connect GitHub** control | GitHub is not available on this deployment, or you are a guest | Sign in; if still missing, the surface is not offered here | -| **Reconnect** | The grant lapsed or was revoked | Choose **Reconnect** and approve on GitHub | -| A repository is missing from the picker | The grant does not cover it | Reconnect and include it | -| You are looking for a token field | There is none | Connect GitHub is the only route; see [Connect GitHub](/code/github) | +| **Isolated environments are not enabled here** and **This deployment has no runtime fleet. Cloud sessions still run.** | the deployment has no fleet behind environments | environments cannot be used here at all. Ordinary Cloud sessions still work | +| **No environment capacity is available: the fleet is scaled to zero. Nothing was started, so nothing was lost.** | there is no capacity right now | press **Try again**. Nothing was half-created that you need to clean up | +| **Sign in to use an isolated environment** | an environment outlives the browser tab that started it, so a guest could never come back to it | sign in | +| A first turn that sits on **Looking for an environment…**, then **Cloning the repository and reading what it declares…**, or **No progress was reported.** | the guest is being prepared and the repository's own install is running | wait. Save the result as an image afterwards so the next session on the same repository and ref skips it | +| **SETUP DID NOT FINISH**, **The environment is not usable yet**, or **The harness could not finish.** | the install did not complete | read the harness transcript on the session's **Runtime** tab, then **Re-run setup**. See [Environments and images](/code/environments) | +| A follow-up wakes the session before it does any work | an idle guest hibernates and the next turn wakes it | expected behaviour, not a fault | +| **This session runs on This PC, and no host is connected. Pair one from the Host pane and the composer comes back.** | a desktop session's host went away | pair a host again, or do the work in a Cloud session. See [Code on desktop](/code/desktop) | +| A terminal run refuses This PC or SSH | a host override is set in your shell and its prerequisites are not met | both need an already connected Code session. Clearing the override returns the run to Cloud. See [Code in the terminal](/code/cli) | +| **Without an isolated guest this deployment cannot run Tower.** | Tower needs an isolated guest and refuses rather than half-running | use a Cloud session on a deployment that has a fleet | +| The **Desktop** tab carries the badge **Soon** | a Code runtime is headless, so there is no screen inside it | there is nothing to enable. It is not available yet | + +## A turn that will not change anything + +Work through these in order. The first two explain almost every case. + +1. **The mode.** **Ask** and **Plan** are built without the tools that write files, edit files or run commands, so a turn in either one cannot change anything however it is worded. The **Changes** pane says so outright: **Ask and Plan do not change files, so there is nothing to review here.** Switch to **Agent** and send again. The tool set is chosen when a turn is built, so a mode change applies to the next turn and never to the one already running. See [Ask, Plan, Agent](/code/interactions). +2. **The write gate.** Writes do not land by themselves. They wait in **Changes** as pending files, and the tree is not written until a person presses **Approve** or **Approve all**. If your files are sitting at **Pending**, that is the answer. See [Changes and diffs](/code/changes). +3. **A denial is not a crash.** **Deny** refuses one call. The turn keeps going and the model is told it was denied, so the transcript continuing after a denial is normal. +4. **A tool you connected elsewhere.** A Code session is given no tool servers, no connectors and no plugins of its own, and it will tell you so: **Off · this session has no MCP access.** and **Off · Chat and Bot access does not carry into Code.** Never plan a session around a tool you connected for the workspace. See [Code integrations](/code/integrations). +5. **A list of safe commands.** There is no command allowlist and no per-directory allowlist in Code. The shell is allowed or withheld as a whole, and each command is put to you when it is asked. See [Permissions and approvals](/code/approvals). + +<Warning> +**There is no undo, no checkpoint and no revert of a turn's edits.** Nothing in Cortex rolls an approved change back. The moment to refuse is while the write is still pending, with **Reject**, and after that your repository's own history on the branch is what you have. Do not plan a session around being able to unwind it afterwards. +</Warning> + +## Session control, follow-ups and decisions + +| What you see | What it means | What to do | +| --- | --- | --- | +| Pressing **Stop** a second time does nothing | the cancel is already recorded | a cancel is a recorded request, not a repeatable button. Wait for the session to read **Stopped** | +| The session reads **Stopped** where you expected **Failed** | a session you cancelled is not a failed one, and is never drawn as an error | press **Continue** to carry on from where you stopped. A genuinely failed turn offers **Try again** instead | +| A follow-up you send has no effect | you are detached from the session | press **Attach**, then send it. Detaching never stopped the turn, it only stopped you sending and deciding | +| **Queued follow-up**, with **Reclaim** | your text is waiting behind the turn that is running | press **Reclaim**, or Escape, to take it back. **Only the owner can return this follow-up.** | +| **That decision could not be recorded** | an approval did not save | decide again. Nothing was allowed while it was unrecorded | +| **That spend decision could not be recorded** | the same, for a spend consent | decide again. A spend decision cannot be changed once it is recorded | +| An approval prompt you expected never appears | not every tool stops and asks on every deployment | the gate you can rely on is the file write in **Changes**. Do not treat a silent tool as a granted one | +| **That agent could not be stopped.** | a nested transcript refused the stop | nested transcripts are read-only and **Stop** is the only control on them. Press it again | +| **Sessions could not be loaded.** with **Retry**, or **The session could not be opened** | the board or the session failed to load | retry, or reload the page. Nothing about the session itself changed | + +## Context and compaction + +| What you see | What it means | What to do | +| --- | --- | --- | +| **Context is full. Compact the session to continue.** | the transcript has outgrown the window | compact it. Put anything that must survive into **Keep in context** first, or press **Compact anyway** | +| **Compaction is not available on this deployment.** | this deployment cannot compact | start a new session and carry over what matters in the first prompt | +| **The session could not be compacted.** | compaction ran and failed | try again, and start a new session if it keeps failing | +| **Earlier turns were compacted** | Cortex has already compacted the session for you | nothing to do. Compaction fails closed, so the turn stops rather than silently dropping history | -## Runtime +## Changes and diffs -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| Code says Cloud compute is unavailable | No Cloud runtime on this deployment right now | Try again later, or use **This PC** on the desktop app or CLI | -| A session is slow to start | The guest is being prepared — the agent is installing what the repository needs | Wait; the timeline shows progress | -| A follow-up wakes the session before working | The guest hibernated while idle | Expected — the turn resumes it first | -| This PC or SSH is refused in the CLI | Those hosts need an already connected Code session | Resume a session that has the host, or unset `CORTEX_COMPUTER`. See [Code on desktop](/code/desktop) | +| **The changes could not be read from the runtime.** | the runtime answered but its working tree could not be read | reopen the session, or wait for the runtime to wake. The pane says this rather than showing you an empty diff | +| **Pending file writes could not be loaded.** | the write gate itself could not be read | reload. Nothing is decided for you while the list is unreadable | +| **No branch yet** or **No pull request** | the session has not pushed anything yet | these are states, not errors. A branch appears once there is work on it | -## The agent will not change anything +## An automation that never ran -Check, in order: +Nothing in Code runs unattended today, and the page says so itself: **Saved instructions only. Schedules and events do not execute yet. Prepare a session, then send an interactive turn to start work.** A saved schedule or event trigger is stored, and it is not executed. Enabling an automation only makes manual preparation available. -1. **Mode.** Ask and Plan withhold the mutating tools. Switch the turn to **Agent**. -2. **In the CLI, the sandbox.** `--sandbox read-only` blocks all writes; `workspace-write` confines them to the project. See [Modes and permissions](/cli/modes-and-permissions). -3. **In the CLI, Spec mode.** Mutating tools stay locked until you accept the plan. -4. **In the CLI, the `permission` table** in `config.toml` can deny `edit` or specific commands outright. `cortex debug config --diff` shows what differs from the defaults. +If you expected a run, use the row's own control to prepare a session, then send a turn to it. See [Automations](/code/automations). ## Cortex Security -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| A check run marked **failed** | The review found issues, or could not run — a review that could not run is stored as failed, never as approved | Read the check run; fix and push | -| No check run on a pull request | The GitHub App is not installed on that repository | Install it from `/code/security` | -| You expected `/security` to show reviews | `cortex.foundation/security` is the public product page | Open `/code/security` in the app | +| A check run marked as failed | the review found something, or it could not run. A review that could not run is stored as failed and never as an approval | read the check run, then see [Security troubleshooting](/security/troubleshooting) | +| No check run on a pull request at all | the Cortex Security GitHub App is not installed on that repository | **Connect GitHub** does not cover it, because it is a separate install. See [Pull-request review](/code/security) | +| You expected a Code session to produce a review | a session writes code, a review reads a pull request, and reviews are not started from a session | open Security for the repository instead | -## Errors +## Usage that looks empty -Every failure is a problem document with a stable `code` and a `request_id`. Common ones in Code: +A session can finish without a matching row appearing on [Usage](/code/usage). The page shows what the account ledger recorded, and a Code turn is not guaranteed to write to it, so token columns can be empty for Code rows. Treat Usage as a record of recorded cost rather than as a count of your sessions. -| Code | Meaning | -| --- | --- | -| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Too many sessions or turns at once on the account | -| [`no_capacity`](/problems/no_capacity) | The farm is full; try again shortly | -| [`invalid_state`](/problems/invalid_state) | The session is not in a state that allows the action — for example a turn is already running | -| [`upstream_timeout`](/problems/upstream_timeout) | The runtime did not answer in time; retry | +## Error codes -Full list: [Problem catalog](/problems). +When a failure has no message of its own, it surfaces as a problem with a stable code. These are the ones a Code user can actually meet. + +| Code | When you meet it | +| --- | --- | +| [`no_capacity`](/problems/no_capacity) | no isolated guest could be placed for the work | +| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | too many sessions at once on the account | +| [`service_unavailable`](/problems/service_unavailable) | the runtime fleet is not answering | +| [`quota_exceeded`](/problems/quota_exceeded) | a saved-environment or runtime ceiling was reached | +| [`invalid_state`](/problems/invalid_state) | the action does not fit the session's state, such as cancelling a cancel that is already recorded | +| [`not_found`](/problems/not_found) | the session no longer exists, or never did | +| [`gone`](/problems/gone) | you reached something that has been retired | +| [`validation_failed`](/problems/validation_failed) | a field was malformed, or a status outside the allowed set was sent | +| [`forbidden`](/problems/forbidden) and [`unauthenticated`](/problems/unauthenticated) | a guest action, or a sign-in that has lapsed | +| [`entitlement_required`](/problems/entitlement_required) | a capability your plan or your deployment does not include | +| [`upstream_failure`](/problems/upstream_failure) and [`upstream_timeout`](/problems/upstream_timeout) | GitHub did not complete, or took too long | + +<Note> +Where a surface has wording of its own you see that instead of a code, and the wording is the better guide. The GitHub connection screens are the clearest example: they translate an upstream failure into **GitHub did not complete the connection** rather than showing you a raw code. +</Note> + +The full set, with a page per code, is in the [Problem catalog](/problems). ## Related -- [Code](/code) — what Code is and who can open it. -- [Ask, Plan, Agent](/code/interactions) — the modes that withhold mutating tools. -- [How Code works](/code/how-it-works) — where workspace tools execute. -- [Troubleshooting](/getting-started/troubleshooting) — the same guidance across all products. +- [Permissions and approvals](/code/approvals) for the two gates and what each answer grants. +- [Changes and diffs](/code/changes) for the write gate, per file and per batch. +- [Cloud runtimes](/code/runtimes) for how a guest is prepared, hibernated and woken. +- [Connect GitHub](/code/github) for every state of the connection. +- [CLI troubleshooting](/cli/troubleshooting) for the same work in a terminal. +- [Troubleshooting](/getting-started/troubleshooting) for problems across all the products. diff --git a/code/usage.mdx b/code/usage.mdx new file mode 100644 index 0000000..d8ee7f3 --- /dev/null +++ b/code/usage.mdx @@ -0,0 +1,78 @@ +--- +title: "Usage" +description: "Read the Usage page: recorded cost and billable actions over a 7, 30 or 90 day window, the breakdowns, and what the ledger can honestly tell you." +icon: "chart-simple" +--- + +**Usage** is the accounting view for your workspace. It reads the ledger that turns write to and shows what was recorded: a total cost, a count of billable actions, the models that were used, and the raw rows behind all three. The page describes itself as **Recorded usage and cost for this workspace, from the ledger each turn writes to.**, and that wording is deliberate. It reports what the ledger holds, not what you are about to be invoiced. + +This page explains the window selector, the three figures at the top, the four breakdowns, and the limits of the data. Read the honesty section before you use these numbers to reconcile anything: there are two places where a reasonable reader draws a wrong conclusion. + +## Choose a window + +One selector, labelled **Usage window**, controls the whole page. It offers **7 days**, **30 days** and **90 days**, and opens on **30 days**. Everything below it, the stats, the chart and the ledger rows, is recomputed for the window you pick. + +## The three figures at the top + +| Figure | What it is | +| --- | --- | +| **Recorded cost** | The cost the ledger recorded in the window. The note under it reads `Over {n} days`. | +| **Billable actions** | How many billable events were recorded. It is a count of events, not of sessions or of turns. | +| **Models used** | How many distinct models appear in the window. | + +## The four breakdowns + +Under the figures the page splits the same data four ways. + +- **COST PER DAY**, a chart of the window. +- **BY KIND**, cost grouped by the kind of activity recorded. +- **BY MODEL**, cost grouped by model. +- **LEDGER**, the rows themselves, with the columns **Date**, **Kind**, **Model**, **Count**, **Cost**, **Tokens** and **Name**. + +When there is nothing to show you get **No usage in this window.**, or **No model usage in this window.** for the model breakdown specifically. + +<Note> +The chart joins only the days that had activity. A quiet day is absent rather than drawn as a zero, so a line that jumps a gap is the chart working correctly, not a rendering fault. Zero-filling is refused on purpose, so that a day with no recorded activity is not presented as a measured zero. +</Note> + +## What the ledger can and cannot tell you + +Two caveats matter more than anything else on this page. + +<Warning> +**Do not treat this page as a complete record of Code activity.** The page reads a ledger, and it is not established that every Code turn writes a row to it. Read the page as "what the ledger recorded" rather than "everything that ran". If a session you remember running does not appear, that is within what the page promises. +</Warning> + +The second caveat is the **Tokens** column. Recorded rows can carry no token counts at all, so the column may simply be empty for rows that came from Code. That is not data loss you can recover from this page, and it means you should not try to reconcile token counts here against anything else. Use the column when it is populated, and ignore it when it is not. + +## Cost is on the account, not the session + +Inside a session, the **SESSION USAGE** meter states the rule outright: + +> **Cost is on the account ledger, not per session.** + +It links to **Account usage**, which is this page. A session row on Code Home or on the sessions board shows a cost suffix **only** when that particular session has a recorded spend, so a row without one is normal and does not mean the session was free. There is no per-session invoice to produce, and there is no per-member split on this page. + +## Spend limits, plan limits, and what is billed + +Two different controls are easy to confuse. + +**Set spend limit** is an action on this page, and it is the control for capping spend. That is all that is documented about it here: the form behind the button is not described, so open it in the app to see what it asks for. + +**Spend consent** is a different thing and lives in a session, not here. When a turn needs to spend, it asks, and you choose to allow it once, allow it up to an amount, or deny it. A decision cannot be changed afterwards. See [Permissions and approvals](/code/approvals). + +Cortex warns before you hit the included amount rather than after. A warning banner appears at **80 %** of the included amount and a reached banner at **100 %**. Those are the only usage percentages worth memorising. Beyond the included amount, the product's own wording applies: + +> **Usage beyond the included amount is billed at API rates. Changes apply at the start of the next billing cycle.** + +<Info> +How much is included, and how many sessions, turns or minutes your plan allows, depends on the plan and is not shown on this page. See [Limits and quotas](/reference/limits) for the figures that apply to your account, and the upgrade dialog in the app, which names your current plan and its price per month. No per-session or per-turn Code allowance is published, so do not plan around one. +</Info> + +## Related + +- [Limits and quotas](/reference/limits) +- [Permissions and approvals](/code/approvals) +- [Code sessions](/code/sessions) +- [Code settings](/code/settings) +- [Cloud runtimes](/code/runtimes) diff --git a/custom.css b/custom.css deleted file mode 100644 index ded23b6..0000000 --- a/custom.css +++ /dev/null @@ -1,252 +0,0 @@ -/* Docs CTAs are ink on cream — not brand-green Install / primary buttons. - Brand green (#1F4945) stays on doodle accents, problem-type copy, and - illustration focus rings / window frames — not filled meadow CTAs. - Native components follow the approved Paper docs layout. */ - -#content img[src*="/images/product/"], -#content img[src*="/images/cli/"], -#content img[src*="/images/banners/"], -#content img[src*="/images/frames/"] { - width: 100%; - height: auto; - border-radius: 12px; -} -/* 40×12 TUI boards are 432 px wide renders of a small terminal; show them at - their own size instead of stretching them across the column. */ -#content img[src*="/images/cli/runtime/40x12/"] { - width: auto; - max-width: 100%; - margin-inline: auto; -} - -:root { - --docs-ink: #1f1d1a; - --docs-cream: #faf8f4; - --docs-bg: #faf8f4; - --docs-rail: #f3f0ea; - --docs-text: #1f1d1a; - --docs-muted: #6e6a62; - --docs-line: #e3dfd7; - --docs-input-line: #d7d1c7; - --docs-hover: #eae6de; - --docs-selected: #e1e5de; - --docs-accent: #1f4945; -} - -.dark { - --docs-bg: #211f1c; - --docs-rail: #1a1815; - --docs-text: #edeae3; - --docs-muted: #b0aaa0; - --docs-line: #3a362f; - --docs-input-line: #575148; - --docs-hover: #302d28; - --docs-selected: #293832; - --docs-accent: #8ac5b9; -} - -/* Public Mintlify IDs and component hooks, not generated utility classes. */ -body, #background-color { background: var(--docs-bg); color: var(--docs-text); } -#content-area > div:has(#header) { background: var(--docs-bg); } -#navbar div:has(.nav-logo) { border-bottom: 0; } -#navbar-transition { background: color-mix(in srgb, var(--docs-bg) 94%, transparent); backdrop-filter: blur(12px); } -#navbar, #sidebar, #table-of-contents, #pagination { font-family: Inter, sans-serif; } -#navbar button, #sidebar a, #sidebar .sidebar-group-header, -#table-of-contents a, #table-of-contents button, #pagination a { - font-family: Inter, sans-serif; - text-transform: none; - letter-spacing: normal; - text-shadow: none; -} -#navbar button { color: var(--docs-muted); } -#navbar .nav-logo { height: 24px; } -#sidebar { background: var(--docs-rail); padding-right: 12px; padding-left: 12px; } -#sidebar .sidebar-group-header { padding-left: 12px; color: var(--docs-muted); font-size: 12px; font-weight: 600; } -#sidebar .sidebar-group a { - border-radius: 7px; - padding: 7px 12px !important; - color: var(--docs-muted); - font-size: 13px; - line-height: 20px; - transition: background-color 120ms, color 120ms; -} -#sidebar .sidebar-group a:hover { background: var(--docs-hover); color: var(--docs-text); } -#sidebar .sidebar-group a[aria-current="page"] { - background: var(--docs-selected); - color: var(--docs-accent); - font-weight: 600; - box-shadow: inset 2px 0 var(--docs-accent); -} -#header .eyebrow { display: none; } -#header #page-title { text-align: left; color: var(--docs-text); font-weight: 600; letter-spacing: -0.035em; line-height: 1.15; } -#header .prose p { text-align: left; color: var(--docs-muted); font-size: 16px; line-height: 1.65; } -#content { color: var(--docs-text); font-size: 16px; line-height: 1.75; } -#content :is(h2, h3, h4) { color: var(--docs-text); letter-spacing: -0.025em; font-weight: 600; } -#content h2 { font-size: 24px; line-height: 1.35; margin-top: 2.5rem; } -#content h3 { font-size: 18px; line-height: 1.5; } -#content :is(p, [data-as="p"]) { margin-block: 1rem; } -#content :is(a:not(.ink-btn), strong) { color: var(--docs-text); } -#content a:not(.ink-btn) { text-underline-offset: 4px; text-decoration-color: var(--docs-accent); } -#content a:not(.ink-btn):hover { color: var(--docs-accent); } -#content :is(th, td) { border-color: var(--docs-line); padding: 12px 16px; font-size: 14px; line-height: 1.6; } -#content th { background: var(--docs-rail); color: var(--docs-text); font-weight: 600; } -#content :is(hr, .card, .callout) { border-color: var(--docs-line); } -#content .card { border-radius: 12px; box-shadow: none; } -#content .card:hover { background: var(--docs-rail); } -/* Banner cards live inside CardGroup grids (2–3 columns). A Card outside a - CardGroup spans the whole content column, so hub pages never place one - alone. Inside the grid, keep every banner the same shape so rows align. */ -#content .card > img, -#content .card img[src*="/images/banners/"] { - display: block; - width: 100%; - height: auto; - aspect-ratio: 3 / 2; - object-fit: cover; - border-radius: 0; - margin: 0; -} -#content pre { border: 1px solid var(--docs-line); border-radius: 10px; } -#table-of-contents { align-items: flex-start; text-align: left; } -#table-of-contents :is(a, button) { text-align: left; font-size: 13px; line-height: 1.6; color: var(--docs-muted); } -#table-of-contents a { padding-block: 6px; } -#table-of-contents .toc-item[data-active] > a { color: var(--docs-accent); text-shadow: none; } -#pagination { border-top: 1px solid var(--docs-line); padding-top: 24px; } -#pagination a { color: var(--docs-muted); font-size: 13px; } -#footer a { color: var(--docs-muted); } -#footer.advanced-footer { background: var(--docs-rail); color: var(--docs-text); font: 14px/18px Inter, sans-serif; } -#footer.advanced-footer > div { padding: 32px; gap: 32px; } -#footer.advanced-footer > div > div:first-child { gap: 32px; flex-wrap: wrap; } -#footer.advanced-footer > div > div:first-child > div { min-width: 0; } -#footer.advanced-footer > div > div:first-child > div:nth-child(2) { gap: 32px; } -#footer.advanced-footer > div > div:first-child > div:nth-child(2) p { color: var(--docs-text); font: 600 14px/18px Inter, sans-serif; } -#footer.advanced-footer a { display: flex; align-items: center; min-height: 44px; font: 14px/18px Inter, sans-serif; text-decoration: none; white-space: normal; } -#footer.advanced-footer > div > div:first-child > div:nth-child(2) > div > div { gap: 4px; } -#footer.advanced-footer a:hover { color: var(--docs-text); text-decoration: underline; text-underline-offset: 4px; } -#footer.advanced-footer button { min-width: 44px; min-height: 44px; color: var(--docs-muted); } - -/* ponytail: observed Mintlify data-assistant-bar hook; recheck on theme upgrades. - Position only the native bar; dashboard availability and visibility stay native. */ -[data-assistant-bar] { position: fixed; inset: auto 24px 24px auto; width: 360px; max-width: calc(100vw - 48px); overflow: visible; } -body:has([data-assistant-bar]:not([aria-hidden="true"])) #footer { padding-bottom: calc(112px + env(safe-area-inset-bottom)); } -.chat-assistant-floating-input::before { content: none; } -.chat-assistant-floating-input > div { padding-bottom: 0; } -.chat-assistant-floating-input > div > div { - background: var(--docs-bg); - border: 1px solid var(--docs-input-line); - border-radius: 14px; -} -.chat-assistant-input { - background: transparent; - color: var(--docs-text); - min-height: 60px; - padding-right: 56px; - font: 14px/20px Inter, sans-serif; -} -.chat-assistant-input::placeholder { color: var(--docs-muted); } -.chat-assistant-send-button { min-width: 44px; min-height: 44px; border-radius: 10px; } -.chat-assistant-send-button:not(:disabled) { background: var(--docs-text); color: var(--docs-bg); } -.chat-assistant-send-button svg { color: inherit; } -#chat-assistant-sheet { background: var(--docs-bg); color: var(--docs-text); border-color: var(--docs-line); font-family: Inter, sans-serif; } -#chat-assistant-sheet .chat-assistant-sheet-header { border-color: var(--docs-line); color: var(--docs-text); } -#chat-assistant-sheet .chat-assistant-sheet-content { color: var(--docs-text); } -#chat-assistant-sheet .chat-assistant-input { background: var(--docs-bg); border-color: var(--docs-line); } -:is(#sidebar, #mobile-nav) .sidebar-group-header svg { transition: transform 160ms ease, color 160ms ease; } -:is(#sidebar, #mobile-nav) .sidebar-group-header:is(:hover, :focus-within) svg { transform: translateY(-1px); color: var(--docs-accent); } -#mobile-nav { background: var(--docs-rail); } -#mobile-nav :is(a, button, .sidebar-group-header) { font-family: Inter, sans-serif; text-transform: none; letter-spacing: normal; } -#mobile-nav .sidebar-group-header { color: var(--docs-muted); } -#mobile-nav .sidebar-group a { min-height: 44px; align-items: center; color: var(--docs-muted); border-radius: 7px; } -#mobile-nav a[aria-current="page"] { background: var(--docs-selected); color: var(--docs-accent); text-shadow: none; font-weight: 600; } -:is(a, button, input, textarea):focus-visible { outline: 2px solid var(--docs-accent) !important; outline-offset: 3px; } -.chat-assistant-floating-input:focus-within { outline: 2px solid var(--docs-accent); outline-offset: 3px; border-radius: 14px; } - -@media (min-width: 1024px) { - #sidebar { width: 248px; padding-top: 76px; } - #content-area { padding-left: 248px; } - #footer.advanced-footer { margin-left: 248px; } - #content-area > div:has(> #header) { max-width: 720px; padding-inline: 32px; } -} -@media (max-width: 1023px) { - #navbar button { min-height: 44px; } - #content-area { padding-inline: 20px; } - #content-area > div:has(> #header) { padding-inline: 0; } - #header #page-title { font-size: 30px; } - #content th, #content td { padding: 10px 12px; } - [data-assistant-bar] { inset: auto 16px calc(16px + env(safe-area-inset-bottom)) 16px; width: auto; max-width: none; } -} -@media (max-width: 767px) { - #footer.advanced-footer > div > div:first-child > div:nth-child(2) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 24px; } -} -@media (prefers-reduced-motion: reduce) { - #sidebar .sidebar-group a { transition: none; } - :is(#sidebar, #mobile-nav) .sidebar-group-header svg { transition: none; transform: none !important; } -} - -.ink-cta-row { - display: flex; - flex-wrap: wrap; - gap: 0.75rem; - margin: 1.25rem 0 2rem; -} - -.ink-btn { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 44px; - padding: 0.5rem 1.1rem; - border-radius: 0.5rem; - border: 1px solid var(--docs-ink); - background: var(--docs-ink); - color: var(--docs-cream) !important; - font-weight: 600; - font-size: 0.9375rem; - line-height: 1.2; - text-decoration: none !important; -} - -.ink-btn:hover { - background: #111110; - border-color: #111110; - color: var(--docs-cream) !important; -} - -.ink-btn-quiet { - background: var(--docs-cream); - color: var(--docs-ink) !important; -} - -.ink-btn-quiet:hover { - background: #f0ece4; - border-color: var(--docs-ink); - color: var(--docs-ink) !important; -} - -.dark .ink-btn { - background: #ece7de; - border-color: #ece7de; - color: var(--docs-ink) !important; -} - -.dark .ink-btn:hover { - background: var(--docs-cream); - border-color: var(--docs-cream); - color: var(--docs-ink) !important; -} - -.dark .ink-btn-quiet { - background: transparent; - border-color: #ece7de; - color: #ece7de !important; -} - -.dark .ink-btn-quiet:hover { - background: #1a1a18; - border-color: var(--docs-cream); - color: var(--docs-cream) !important; -} - -:is(.dark) .status-cortex-logo { - content: url("/logo/banner-dark.png"); -} diff --git a/design/bot-jobs.mdx b/design/bot-jobs.mdx new file mode 100644 index 0000000..39b3e22 --- /dev/null +++ b/design/bot-jobs.mdx @@ -0,0 +1,56 @@ +--- +title: "Bot jobs" +description: "What the Bot jobs surface in Cortex Design is meant for, why handing a design to a Cortex Bot is not available yet, and what to do instead." +icon: "robot" +--- + +Bot jobs is the surface where you would hand a design task to one of your Cortex Bots: give it a canvas and a brief, let it work while you do something else, and come back to what it produced. That is the intent. + +**It is not available yet, and there is nothing to switch on.** The Design desktop app draws the surface, but no work is behind it. A Cortex Bot cannot open, read, or change a design canvas today, so nothing you submit from these controls starts anything. This page says what the surface is for, what you can do instead right now, and what will change when it ships. + +<Warning> + Handing a design to a Cortex Bot is planned, not shipped. Treat the **Bot jobs** row in the sidebar, the **Hand to Bot** button in the editor header, and the **Hand to a Bot** sheet as the shape of a feature under construction rather than as controls that do something. +</Warning> + +## What you are looking at + +The Design desktop app's sidebar carries a **Bot jobs** row, and the editor header carries a **Hand to Bot** button that opens a sheet asking which bot, what kind of job, and which part of the canvas to work on. Those controls are drawn, and they are the right place to look when the feature arrives. What they are not is wired: there is no service behind them, so a submitted brief does not reach a bot and no job appears anywhere. + +For the same reason, do not read the screen as a status board. Nothing is queued, nothing is running, and there is no result waiting for review. + +## What to do instead today + +Do the design work in the Design desktop app yourself, and use Cortex Bot for the work it can already do. + +<CardGroup cols={2}> + <Card title="Cortex Bot" icon="robot" href="/bot"> + What a bot is, what it can reach, and how to talk to one. Start here rather than from Design. + </Card> + <Card title="Tasks" icon="list-check" href="/bot/tasks"> + Give a bot a piece of work and follow it, on the surfaces where that already works. + </Card> + <Card title="Routines" icon="repeat" href="/bot/routines"> + Have a bot do something on a schedule, rather than waiting for design jobs to land. + </Card> + <Card title="Generate and edit" icon="pen-ruler" href="/design/editor"> + Ask Cortex for frames in the canvas thread. This is the working path for design work today. + </Card> +</CardGroup> + +The editor thread is the closest thing to what Bot jobs promises. You describe the change you want, Cortex draws it onto the canvas, and every save becomes a numbered version you can read or restore later. The difference is that you are in the room while it happens, rather than reviewing afterwards. + +## What will change when it ships + +Two things sit on the list for the next version of Cortex Design and both matter here: bot tasks, and live updates. Until they land: + +- A bot has no ability to read or write a design canvas, which is the missing piece rather than a permission you can grant. +- Canvas state is refreshed rather than streamed. While Cortex draws, the canvas reports a drawing state and the app refreshes it, so even a working job surface would be something you check rather than something that pushes at you. The Bot jobs header says as much about live updates itself. + +When both ship, expect this page to describe the real flow: picking a bot, scoping the brief to a frame or a whole canvas, and reviewing the version that comes back. Watch the [changelog](/changelog) for it. + +## Related + +- [Cortex Bot](/bot) - what bots do today. +- [Generate and edit](/design/editor) - the working way to change a canvas now. +- [Versions](/design/versions) - the history every save leaves behind. +- [Design troubleshooting](/design/troubleshooting) - Design surfaces that refuse or fail. diff --git a/design/canvases.mdx b/design/canvases.mdx index 9027284..50eedc3 100644 --- a/design/canvases.mdx +++ b/design/canvases.mdx @@ -1,53 +1,142 @@ --- title: "Design canvases" -sidebarTitle: "Canvases" -description: "Boards you host from Chat or Code — frames, notes, options, and the host binding. Default title Untitled canvas; deleting hides it from the list." -keywords: ["board", "frames", "notes", "options"] +description: "What a design canvas holds, the thread that hosts it, the canvases rail, the Designs gallery, renaming, deleting and the 200-canvas cap." +icon: "object-group" --- -A Design canvas starts life as **Untitled canvas**, created the moment Chat or Code writes to it. It belongs to your account, remembers which conversation or session hosted it, and is edited in the [Design desktop app](/design/desktop). +A **design canvas** is the unit of work in Cortex Design: a persistent board of frames, notes and images with a reference of its own, the one you paste between surfaces. Every canvas is created from, and stays linked to, one thread. That thread is the canvas's **host**, and a host is a Cortex Chat conversation or a Cortex Code session, never both at once. -## What lives on the board +This page covers what lives on a canvas, how a canvas is created and which thread it belongs to, the two places canvases are listed, and what happens when you rename or delete one. It ends with the limits that apply. -| On the canvas | Not this object | +## What a canvas holds + +| On the canvas | What it is | | --- | --- | -| **Frames** — screens, diagrams, layouts | A Chat project | -| **Notes** — annotations beside the frames | A Chat canvas (a document beside a conversation) | -| **Options** — alternatives laid out side by side | A Code workspace file | -| **Host binding** — the Chat conversation or Code session that created it | A Bot's computer — Bot does not receive design tools | -| **Library drawer** — components, pages, tokens | Chat's file [Library](/chat/library) | +| **Frames** | The boards Cortex draws on: a screen, a layout, a diagram. When Cortex answers one brief with alternatives, each alternative is a frame carrying a short option letter, A, B, C. In the product's vocabulary those frames are the options you pick between. A page, in the sense of a screen, is a frame. | +| **Notes** | Text you or Cortex leave on the board, up to 16,384 characters each. | +| **Library drops** | Components, tokens and pages you reuse from your [Design library](/design/library). | +| **Images** | Picture fills placed on the board. They must be raster images: SVG is not accepted as a canvas asset. | + +A new canvas is titled **Untitled canvas** until you rename it, and its host defaults to Chat. + +### Not the same as the other canvases + +Three things in Cortex are called a canvas or look like one, and they are separate objects that share no storage. -## Create and open +| Thing | What it is | Where it opens | +| --- | --- | --- | +| A **design canvas** | The visual board described on this page, with a reference of the shape `dcn_…` | The Cortex Design desktop app | +| A [Chat canvas](/chat/canvases) | A markdown document written beside one conversation, not a board of frames | Cortex Chat | +| A [Chat project](/chat/projects) | A folder that groups conversations and files | Cortex Chat | + +## Create a canvas + +There are three ways in, and they produce the same object. <Steps> - <Step title="Sign in"> - Another account's canvases are not visible; a guest cannot create one. - </Step> - <Step title="Host a canvas from Chat or Code"> - The design tools create the board and write the first frames. The title is **Untitled canvas** until you rename it. + <Step title="Ask for it inside a Chat or Code turn"> + Ask Cortex for the design in the thread. If it draws without naming an existing canvas, a new canvas is created and bound to the thread you are in. Cortex confirms in the transcript with a line naming the canvas, its revision and its counts, and says it can be opened in Cortex Design. + + From a Code session, a mode that only answers or only plans can read a canvas but not write one. Use a mode that can act. See [Ask, Plan, Agent](/code/interactions). </Step> - <Step title="Open the working UI on desktop"> - Edit frames, notes, and options in the [Design desktop app](/design/desktop). + <Step title="Use New canvas in the rail"> + The **CANVASES** rail beside a thread has a **New canvas** control, which creates an empty canvas hosted by that thread. </Step> - <Step title="Delete when done"> - Deleting a canvas hides it from the list. + <Step title="Use New design in the desktop app"> + In the Design window, **New design** (`⌘N`) opens a sheet asking for a **NAME**, what to **START FROM**, a **BRIEF**, and a **MODEL**. The [Design quickstart](/design/quickstart) walks through it field by field. </Step> </Steps> -## Who can open one +## The host thread + +A canvas remembers which thread produced it, and the binding can be changed after the fact: + +- Attach a conversation and the canvas becomes Chat-hosted; any Code session binding is cleared. +- Attach a Code session and the canvas becomes Code-hosted; any conversation binding is cleared. +- Clear the binding and the canvas keeps its contents but shows no thread. +- Attaching both kinds at once is refused: `A Design canvas binds a Chat conversation or a Code session, not both.` +- You have to own the thread you are binding to. Another account's thread answers as not found. + +Deleting the host thread does **not** delete the canvas. It only unbinds it, and the canvas then shows no thread. + +## The canvases rail, in the web app + +Beside an open Chat thread or Code session, the rail is headed **CANVASES** and lists only the canvases whose host matches that surface *and* that thread. A Chat thread never shows Code canvases. + +| What you see | What it means | +| --- | --- | +| Row title, then the host and thread title and a time | Which thread the canvas belongs to. The host reads `Chat`, `Code` or `Unknown`, and an unbound canvas reads `No thread`. | +| Artifact counts, such as `3 frames`, `1 option`, `5 notes` | What is on the board. A board with nothing on it reads `Empty`. | +| A status pill: **Idle**, **In flight**, **Ready** or **Failed** | Nothing on it yet, still being drawn, finished, or at least one thing failed. | +| Day headings such as `TODAY` and `YESTERDAY` | Rows are grouped by when each canvas was last updated. | +| **Search canvases** | Filters on the canvas title and on the host thread title. | +| **Collapse** and **Expand** | On a wide window the rail is a right-hand column; on a narrow one it becomes a collapsed strip under the pane, so the transcript keeps its width until you ask for it. | +| **Copy reference** | Copies the canvas id, which is the address the Design app accepts. A browser that blocks the clipboard says so. | +| **Open in Design** | Drawn only when the app can be reached from the browser. Otherwise copy the reference and paste it in. | + +If the list is long the rail says that it is showing the first canvases and that older ones are not listed yet. If it cannot load, it says `Canvases could not be loaded.` and offers **Retry**. A signed-out visitor gets no rail at all: it draws nothing rather than showing a locked state. + +## The Designs gallery, in the desktop app + +The Design window opens on **Designs**, every canvas in your account rather than one thread's worth. + +| Control | Options | +| --- | --- | +| **View** | `Grid` or `List` | +| Filter chips | `All`, `Mine`, `Bot-managed`, `From Chat`, `From Code` | +| Sort | `Last edited` | +| Grouping | Day headings such as `Today` and `Earlier this week` | + +Each tile carries a version badge such as `V7` and a source chip saying where the design came from: `Chat`, `Code`, `Bot`, `Library` or `Blank`. The header line under the title reports the state of the list: `Nothing here yet` before you have made anything, `Syncing your designs…` while it loads, and a count with the last sync time once it is loaded. + +When the service cannot be reached, the gallery does not pretend. It shows `Couldn't reach Cortex — showing last sync {time}`, or a banner headed `Couldn't load your designs` explaining that the list is your last sync, with **Work offline** and **Retry**. Canvases you already have open stay readable from the local cache, and edits queue and sync when you reconnect. + +<Note> + The `Bot-managed` filter belongs to a capability that is not available yet: a Cortex Bot cannot open or change a design canvas today, so nothing is bot-managed. See [Bot jobs](/design/bot-jobs). +</Note> -A canvas is a member object. Sign in first: a guest has no design tools to host a board with, and another account's canvases are never listed. That is the same rule as the rest of Cortex — a session that cannot be signed back into to revoke something never gets to create it. See [Accounts](/getting-started/accounts). +## Rename a design -## Renaming +Rename a design from the Design window. The host binding is unaffected, so the thread that started it still points at the same canvas. A title is at most 200 characters; a longer one is refused with `A canvas title is at most 200 characters.` -Rename the board from the desktop app. The host binding stays, so the Chat conversation or Code session that created it still points at the same canvas. +The names you give your canvases, and the thread titles shown beside them, are encrypted at rest. See [Security and privacy](/reference/security-and-privacy). + +## Delete a design + +Deleting a canvas **hides** it. Its versions and its images stay, so the canvas can come back. + +1. Choose delete on the design. The app confirms with a dialog naming the design, lists what goes with it, and offers **Keep it** or **Delete design**. +2. A toast then offers **Undo** for ten seconds. +3. After that window the canvas stays hidden until you restore it, permanently delete it, or erase the account. The general retention sweep does not remove design canvases you still hold. +4. The thread the design came from is not affected. + +<Warning> + A hidden canvas still counts as yours until it is permanently deleted, so it still occupies one of your 200 canvases. If you are at the cap, permanently delete a hidden canvas rather than only hiding another one. +</Warning> + +## Limits + +| Limit | Value | +| --- | --- | +| Design canvases per account | **200** | +| Canvas title | 200 characters | +| Host thread title | 200 characters | +| Nodes on one canvas | 8,000 | +| Canvas document, uncompressed | 8 MiB | +| One image, thumbnail or tile | 8 MB | +| A note | 16,384 characters | +| A frame or note name | 200 characters | +| **NAME** in the New design sheet | 48 characters | +| Default page size | 1440 × 900 | -## Chat canvases are a different thing +Creating a canvas past the cap is refused with `This account already has the maximum number of Design canvases.` See [Quota exceeded](/problems/quota_exceeded). A canvas past the document limit is refused on save with `This canvas is too large to save.`, and one with too many pieces on it with `This canvas has too many nodes.` Split the work across canvases when you hit either. -A Chat canvas is a document beside a conversation — see [Chat canvases](/chat/canvases). A Design canvas is a board of frames. Chat can host both; only the Design canvas opens in the desktop app. +A signed-out visitor is refused on every Design surface with `Design canvases need an account. Sign in to keep your work.` See [Entitlement required](/problems/entitlement_required). A canvas that belongs to another account answers exactly as one that does not exist, because Cortex does not reveal whether a canvas exists outside your account. See [Not found](/problems/not_found). ## Related -- [Library](/design/library) — reusable components, pages, and tokens. -- [Design desktop](/design/desktop) -- [Design troubleshooting](/design/troubleshooting) — a board that is missing, or will not rename. +- [Generate and edit](/design/editor) - what the editor does with a canvas once you open it. +- [Versions](/design/versions) - every save is a version, and how to go back to one. +- [Design library](/design/library) - the components, tokens and pages you drop on a board. +- [Export a design](/design/export) - get a PNG or the canvas document out. +- [Design troubleshooting](/design/troubleshooting) - the refusals above, with what to do. diff --git a/design/desktop.mdx b/design/desktop.mdx index 8fe7479..70a99c5 100644 --- a/design/desktop.mdx +++ b/design/desktop.mdx @@ -1,55 +1,153 @@ --- -title: "Design desktop" -description: "The working UI for Cortex Design is a separate desktop app. Chat and Code create canvases; you edit them here." -keywords: ["app", "download", "editor"] +title: "Design desktop app" +description: "The Cortex Design window: its sidebar, the Designs gallery, light and dark, offline states, and the download that is not published yet." +icon: "desktop" --- -The Design working UI is a desktop app of its own. The web app creates and lists canvases when Chat or Code hosts one; editing frames, notes, options, and the Library drawer happens here. +The **Cortex Design** window is the application that edits design canvases. Cortex Design has two +surfaces and only two: a **CANVASES** rail beside a Cortex Chat thread or a Cortex Code session, +which creates and lists canvases, and this window, which does the editing. There is no Design page +in the browser and no Design entry in the product switcher, so the window is not an optional extra +for power users. It is the editor. -## Install +One thing to settle before anything else: Cortex does not publish a download for this window yet, +so this page is not an install guide. What follows describes the window as it is built, so the +vocabulary matches when a build reaches you: the sidebar and its four destinations, the gallery it +opens on, the screens behind the other rows, light and dark, and the offline states. -<Steps> - <Step title="Download"> - Desktop builds are published at [releases.cortex.foundation](https://releases.cortex.foundation). Pick the Design desktop app for your platform. - </Step> - <Step title="Sign in"> - Same account as the web app. Canvases are member objects. - </Step> - <Step title="Open a canvas"> - Your canvases follow your account. Boards hosted from Chat or Code are already listed. - </Step> -</Steps> +## Getting the window -## Work on a board +<Warning> +No installer for the Cortex Design window is published yet. There is no platform list, no updater +of its own, and no sign-in procedure to give you, and Cortex publishes no public download page for +its desktop applications. [Ways to run Cortex](/getting-started/downloads) lists the applications +you can run today, and is where this one will appear once it can be downloaded. +</Warning> -Edit frames and notes, lay out options side by side, and pull components, pages, and tokens from the Library drawer. Rename the board from **Untitled canvas** to something useful; the host binding to the originating Chat conversation or Code session stays. +There is no editor in the browser to fall back on in the meantime. What you can still do from the +**CANVASES** rail in a Chat thread or a Code session is ask Cortex for a design, create an empty +canvas with **New canvas**, read each canvas's counts and status, and use **Copy reference** to +copy the canvas id that the Design window accepts as an address. Generating and editing frames, the +version history, the library and export all live in the window. -## What the web app will not do +Design needs a Cortex account. Every Design surface refuses a visitor who is not signed in, and the +window draws that refusal as a dialog headed `Cortex Design is part of your Cortex account.` -| | Web app | Design desktop | -| --- | --- | --- | -| Create a canvas from Chat or Code | Yes | — | -| List your canvases | Yes | Yes | -| Edit frames, notes, options | No | Yes | -| Library drawer | No | Yes | -| Design segment on the Chat · Code · Bot switcher | No | — | +## The sidebar -## Your boards follow the account +The sidebar carries the **Cortex Design** wordmark, a **New design** action beside it, and a search +field whose placeholder is **Search designs, frames, notes** with a **⌘K** badge. **Collapse +sidebar** narrows it when you want the canvas wider. Below the search field there are four +destinations, and nothing else: -Sign in with the same account you use on the web and your canvases are already listed — the boards a Chat conversation or a Code session hosted are not tied to the machine that created them. Another account's canvases are never visible. See [Canvases](/design/canvases) and [Accounts](/getting-started/accounts). +| Destination | What is there | +| --- | --- | +| **Designs** | Every design in your account, newest first, as a grid or a list | +| **Library** | Your components, tokens and pages, mirrored read-only in this window | +| **Plugins** | Your connectors, with a meta line counting how many are connected | +| **Bot jobs** | The surface for handing a design to a Cortex Bot, which is not available yet | + +Under them a **RECENT** section lists what you opened last. Before you have opened anything it +reads `Designs you open show up here, most recent first.` Your identity and the **Settings** +control sit in the footer. + +There is no Chat or Code switcher in this window, by design. The Settings dialog says so in one +line of its own: `Code editor preferences stay in Cortex Code. This window is Design-only`. The +bindings the window advertises are `⌘N` for a new design, `⌘ \` to toggle the sidebar, `⌘K` to +focus the search field, `⌘E` to export, and `↵` to send your message in the editor thread. + +## Designs, the screen it opens on + +**Designs** is the landing screen and the gallery of every canvas you own, rather than one thread's +worth. Its header line reports the state of the list, rows are grouped under day headings such as +`Today` and `Earlier this week`, and there is a **Grid** or **List** view, filter chips and a +`Last edited` sort. [Design canvases](/design/canvases) covers the gallery control by control. + +Before you have made anything the screen reads `Your first design starts as a sentence.` There are +three ways to get past it. Ask Cortex for the design inside a Chat thread or a Code session, use +**New canvas** in the rail beside that thread, or use **New design** here. Handing a brief to a +Cortex Bot is a fourth route the window suggests, and it is not available yet. + +**New design** (`⌘N`) opens a sheet with four fields: **NAME**, of up to 48 characters, **START +FROM**, a **BRIEF** that becomes the first message in the design's thread, and **MODEL**. **Create +design** (`⌘↵`) makes it. + +<Note> +An account can keep up to **200 design canvases**, and that is the only cap on how many designs you +can have. There is no daily allowance, no monthly allowance and no separate per-plan figure for +Design. A deleted design is hidden rather than erased, and a hidden canvas is still yours, so it +still occupies one of the 200. +</Note> + +Deleting a design starts with a dialog that names it, lists what goes with it, and offers **Keep +it** or **Delete design**. A toast then offers **Undo** for ten seconds. Let that window pass and +the design is hidden, with its versions and images kept, until you restore it or permanently delete +it. The Chat thread that started the design is not touched either way. + +## Library, Plugins and Bot jobs -## Three desktop apps +**Library** is a read-only mirror in this window of the components, tokens and pages your account +reuses across canvases. Its tabs are **Components**, **Tokens** and **Pages**, each with a count, +and **Sync** pulls the library again after you have added items elsewhere. The tab strip carries a +fourth tab listing saved design files, which are files rather than library items and are not one of +the three kinds. See [Design library](/design/library). -| App | Carries | +**Plugins** is the same connector catalogue as the rest of Cortex, with a chip on each card marking +which surfaces that connector reaches, Design among them, and the sidebar row counts how many you +have connected. When a connector's authorisation lapses the window raises an authorisation-expired +toast with a **Reconnect** action. See [Design connectors](/design/plugins). + +**Bot jobs** is drawn, and nothing is behind it. A Cortex Bot cannot open, read or change a design +canvas today, so the row, the **Hand to a Bot** sheet and the editor's **Hand to Bot** button start +nothing. [Bot jobs](/design/bot-jobs) explains what is planned. + +Inside a canvas you get the editor itself: the board, a thread rail where you ask for changes, a +**Versions** button, and **Export**. The **Export** sheet offers **PNG**, which the window renders +on your own machine, and **JSON**, the canvas document. **SVG** and **PDF** are drawn in the same +sheet but disabled and marked for the next version. See [Generate and edit](/design/editor), +[Versions](/design/versions) and [Export a design](/design/export). + +## Light and dark + +**Settings → General** holds a **Theme** row with **Light**, **Dark** and **System**. The choice is +remembered on the machine you set it on rather than carried with your account, so it does not +follow you to another computer, and the window opens light until you change it. The **System** +option is offered but does not follow your operating system's own light or dark setting yet, so +pick **Light** or **Dark** explicitly. + +Several other rows in Settings are drawn with a **COMING SOON** or **SOON** chip, including the +default model, the default thinking level, reasoning summaries, the answer font, chat-history +retention and the data export. [Design settings](/design/settings) goes pane by pane. + +## When Cortex cannot be reached + +The window is built to stay usable when the Design service cannot be reached, and to say so rather +than to look empty. + +| What you see | What it means | | --- | --- | -| [Cortex desktop](/getting-started/desktop) | Chat and Code, with This PC and SSH hosts | -| [Cortex Bot desktop](/bot/desktop) | Agents, routines, channels | -| **Cortex Design desktop** | Canvases and the Library drawer | +| `Syncing your designs…` | The list is loading, which never looks like a list that is empty. | +| `{n} designs · synced {time}` | The list is live and current. | +| `Nothing here yet` | The list loaded and you have no designs. | +| `Couldn't reach Cortex — showing last sync` with a time | You are offline and reading the last list that arrived. | +| `Couldn't load your designs`, with **Work offline** and **Retry** | The service did not answer. Keep reading the last sync, or try again. | +| `Couldn't load connectors`, with **Retry** | The connectors page could not load. Connections you already have stay active. | +| `Offline · retrying in 15s` | A pill on the canvas-not-available state, shown while the window waits before trying again. | + +While you are offline, canvases you already have open stay readable from the copy on your machine, +and edits queue and sync when the connection comes back. If your sign-in lapses while the window is +open you get a dialog headed `Your session expired`, and work done in the meantime is kept on the +machine and syncs when you are back in. -See [Downloads](/getting-started/downloads) for the full list. +A canvas the window cannot fetch gets its own state, headed `This canvas isn't available`, with +**Back to Designs**. Cortex answers the same way for a canvas that was deleted and one that belongs +to another account. [Design troubleshooting](/design/troubleshooting) maps every Design refusal to +what to do about it. ## Related -- [Canvases](/design/canvases) · [Library](/design/library) -- [Chat canvases](/chat/canvases) — the document sidecar, which stays in the browser. -- [Design troubleshooting](/design/troubleshooting) — when the app or a board does not appear. +- [Cortex Design](/design) for what the product is and how its two surfaces divide the work. +- [Design canvases](/design/canvases) for the gallery, the rail, renaming, deleting and the caps. +- [Design settings](/design/settings) for the panes inside this window. +- [Design troubleshooting](/design/troubleshooting) when a canvas or the window itself refuses. +- [Ways to run Cortex](/getting-started/downloads) for the applications you can run today. diff --git a/design/editor.mdx b/design/editor.mdx new file mode 100644 index 0000000..ddd3c6b --- /dev/null +++ b/design/editor.mdx @@ -0,0 +1,127 @@ +--- +title: "Generate and edit" +description: "The Cortex Design editor: generate options as lettered frames, pick one, ask for a change, choose a model, and retry an option that failed." +icon: "wand-magic-sparkles" +--- + +The editor is the screen you spend your time in. It puts three things side by side: the canvas itself, a thread where you ask for what you want, and the controls that save, version and export the result. You get there by opening a design from the **Designs** gallery, or by opening a canvas reference from the **CANVASES** rail in a Chat thread or Code session. + +This page covers generating options, choosing between them, editing a frame by asking for a change, the model picker, and what to do when one option does not finish. [Versions](/design/versions) covers the history the editor is writing, and [Export a design](/design/export) covers getting the result out. + +## The editor at a glance + +| Area | What it is for | +| --- | --- | +| Header | A status pill and a meta line describing the canvas right now, plus **Versions** with a count, **Hand to Bot**, **Export**, and **Toggle thread**. | +| Canvas | The board. A **Library** overlay button, a zoom read-out, and a small toolbar labelled **Canvas tools**. | +| Thread rail | Where you ask for changes, with an **Attach** control, **Send**, and a chip showing the model and thinking level in use. | + +The status pill is the fastest way to know what the canvas is doing: + +| Pill | What it means | +| --- | --- | +| `Blank · unsaved` | A new canvas with nothing on it. | +| `Drawing · 1 of 3` | Cortex is drawing, and how far along it is. | +| `Editing · streaming into B` | A change you asked for is landing in frame B. | +| `Saved` | Everything on the canvas has finished. | +| `Saved · v1 · C failed` | Saved, but one option did not finish. | +| `Viewing v4 · read-only` | You are looking at an earlier version, not the current one. | + +The meta line underneath says the same thing in words, for example `Blank canvas · drawing frame A of 3`, or `New design · 2 of 3 frames · option C did not finish`, or for a hosted canvas the host thread and the counts. + +<Note> + Design does not push live updates to you. While Cortex draws, the canvas carries a drawing state and the app refreshes it, rather than receiving a live stream. A frame that seems to sit still for a moment is normal. +</Note> + +## Generate options + +Describe what you want in the thread rail, in the composer marked **Ask for a change on any frame…**, and send with `↵`. + +Cortex usually answers one brief with alternatives rather than a single result. Each alternative is a frame carrying a short option letter, so a three-way answer arrives as frames **A**, **B** and **C** for the same brief. In the product's vocabulary those frames *are* the options. + +While the work runs: + +- The header reads **Drawing** with a count of how many frames are done. +- Each frame card shows its own state: `Drawing…`, `Queued`, `Streaming` or `Failed`. +- A finished frame carries its version badge instead. + +On a canvas with nothing on it, the board explains itself rather than sitting blank. It reads **Nothing on the canvas yet**, says that Cortex places frames there as it designs, and offers **Open Library** and **Add a note** so you have something to do while you wait. + +## Pick a frame and edit it + +A frame card is drawn as its option letter and its title, so the second option reads as `B` and its name. + +<Steps> + <Step title="Select the frame you want"> + Selecting a frame draws its size as a read-out and an **Edit** control on the card. + </Step> + <Step title="Ask for the change in the thread"> + Say what should be different. The header switches to an editing state naming the frame, for example `Editing · streaming into B`, and that frame's card shows `Streaming` while the change is applied. The rest of the canvas is left alone. + </Step> + <Step title="Keep going, or take another option further"> + Each round of changes is saved as a new version, so you can compare where two options ended up without losing either. Options you do not want can be removed from the board. + </Step> +</Steps> + +The thread rail tells you when a save has landed, with a line such as `Saved as v7` followed by the time and the frame and note counts. The hint under the composer tells you what the rail is doing: whether edits are landing on the canvas as they arrive, or whether a stream is running and can be stopped. + +### The canvas toolbar + +The board carries a small toolbar labelled **Canvas tools** with five icon-only controls. Their icons read as select, a frame, a note, a grid and text, and none of them carries a written label, so this page does not name them. The reliable moves are the two the app documents for you: select a frame to edit it, and add a note. + +The **Library** overlay button opens your [Design library](/design/library) over the board, so a component can be dragged straight onto a frame. + +## Choose a model and a thinking level + +The chip in the thread rail shows the model that will draw and the thinking level it will use. + +<Steps> + <Step title="Open the chip"> + It opens a picker with a **Filter models** field for when the list is long. + </Step> + <Step title="Pick a model"> + A model in preview is marked `PREVIEW`. A model your plan does not include is shown with `Not on plan` and cannot be chosen. + </Step> + <Step title="Set the thinking level"> + A segmented control offers **Low**, **Medium** and **High**. Higher levels spend more time reasoning before drawing. + </Step> +</Steps> + +Which models are offered, and what each is good at, belongs to [Models](/reference/models) rather than to this page. The Design window's own **Settings → Models** pane carries a banner about plan availability, quoted in full on [Design settings](/design/settings). In practice every published model is available from the Free plan up. + +## When an option fails + +One option failing does not spoil the rest of the board. The frame that could not finish shows **Failed**, and its card says so in plain words along with the reason the attempt stopped. + +You get two controls, on the card and again in the thread: + +- **Retry option C** (or **Retry C** in the thread) runs that option again, leaving the finished frames alone. +- **Remove frame** drops it and keeps the rest of the canvas. + +<Warning> + A canvas reports the worst state it contains. One failed frame makes the whole canvas read **Failed**, even while another frame is still being drawn. Retry or remove the failed frame and the canvas goes back to reporting what the rest of the board is doing. +</Warning> + +## How saving works here + +Every save creates a new version, numbered from 1 upwards, and the canvas records which one is current. `v7` in the interface is the seventh save of that canvas. You do not choose when to snapshot: the service keeps history cheap to replay on its own. + +Saving is optimistic about two windows at once. If you save a canvas that another window has already moved on from, the save is refused with `This canvas was saved from another tab. Reload and try again.` Reload the canvas and redo the change. See [Conflict](/problems/conflict). + +## What Cortex draws, and what you can build by hand + +Cortex's own drawing covers **frames, images and notes**, and the top level of a canvas is frames. Asking it for other kinds of shape gets a plain refusal saying it writes frames, images and notes. + +The editor itself accepts more than that. A board you build by hand in the Design window can hold groups, rectangles, ellipses, vectors, text, component instances and more, so the app can build richer canvases than Cortex generates for you today. + +## Handing a frame to a Bot + +The editor header carries **Hand to Bot**, and the sidebar has a **Bot jobs** entry. This is the shape of a capability that is **not available yet**: a Cortex Bot cannot open or change a design canvas today. [Bot jobs](/design/bot-jobs) explains what is planned and what a Bot can do for you in the meantime. + +## Related + +- [Design canvases](/design/canvases) - the board, its host thread, and where canvases are listed. +- [Versions](/design/versions) - view or restore an earlier save. +- [Design library](/design/library) - the components, tokens and pages you drop on a frame. +- [Export a design](/design/export) - PNG, JSON, scope and scale. +- [Design troubleshooting](/design/troubleshooting) - a canvas that will not save, and other refusals. diff --git a/design/export.mdx b/design/export.mdx new file mode 100644 index 0000000..cf6cf30 --- /dev/null +++ b/design/export.mdx @@ -0,0 +1,70 @@ +--- +title: "Export a design" +description: "Take a frame, a selection, or a whole canvas out of Cortex Design as a PNG rendered on your machine or as the canvas document in JSON." +icon: "file-export" +--- + +Export turns part of a design canvas into a file you can hand to someone else or commit alongside your code. Today it produces two things: a **PNG** that the Design desktop app renders on your own machine, and the canvas document as **JSON**. Each canvas also keeps a stored thumbnail, which is the small picture other Cortex surfaces show for it. + +This page covers what you get today, how to run an export from the editor, what the scope and scale choices do, and which formats are planned but not available yet. Export is a Design desktop app action: the canvases rail in the web app lists a canvas and copies its reference, but does not export it. + +## What you can produce today + +| Format | Available | What it is | +| --- | --- | --- | +| **PNG** | Yes | A raster picture of the scope you chose, rendered locally by the app | +| **JSON** | Yes | The canvas document itself, frames and notes and all | +| **SVG** | Not yet, planned for v1.1 | Shown in the sheet and not selectable | +| **PDF** | Not yet, planned for v1.1 | Shown in the sheet and not selectable | + +The export sheet is honest about this itself: it carries a **PARTIAL IN V1** chip, and the SVG and PDF rows are drawn disabled with a `v1.1` marker beside them. Choosing them does nothing until they ship. + +Export produces image and document files only. There is no export to a web page, and no export to a slide deck. + +## Run an export + +<Steps> + <Step title="Open Export in the editor header"> + The sheet opens over the canvas. The keyboard shortcut for the confirm button is `⌘E`. + </Step> + <Step title="Choose the SCOPE"> + Three choices: the current **Selection**, which names the frame you have picked; **All frames**, with their count; or **Canvas**, meaning the whole board including anything outside the frames. + </Step> + <Step title="Choose the FORMAT"> + **PNG · rendered here** or **JSON**. The two planned formats sit below them, disabled. + </Step> + <Step title="Choose the SCALE"> + **1x**, **2x**, or **3x**. This applies to a PNG; it has no meaning for the JSON document. + </Step> + <Step title="Choose the DESTINATION"> + Download the file to this computer, which is selected by default and lands in your downloads folder, or copy it to the clipboard. + </Step> + <Step title="Confirm"> + The button names the format you picked. Before you press it, the sheet shows an estimate of what you are about to produce: how many frames, the pixel dimensions, and the approximate file size. + </Step> +</Steps> + +## What each format is good for + +**PNG** is the one to reach for when a person is going to look at the result: a review comment, a message, a document. It is rendered by the app on your machine rather than by the service, which is why the format row says so and why the app has to be open to produce one. Use `2x` or `3x` when the picture will be viewed on a high-density screen or scaled up. + +**JSON** is the canvas document: the frames, their positions, the notes, and the references to the images on the board. Reach for it when something other than a person is going to read the result, or when you want a copy of the design in your own repository. It is the whole document rather than a picture of it, so it does not depend on a scale. + +The **thumbnail** is not something you pick in the sheet. Each canvas carries one, uploaded as an image on that canvas, and it is what a canvas tile shows in a list. A thumbnail must be a raster image; `SVG is not stored as a Design asset.` + +## Limits worth knowing + +- An uploaded image, thumbnail, or tile is at most 8 MB. Past that, `A Design asset is at most 8 MB.` +- SVG is not accepted as an image on a canvas, so convert artwork to PNG before placing it. +- A canvas document is capped at 8 MiB uncompressed and 8,000 nodes. A canvas that has outgrown those answers `This canvas is too large to save.`, which you will meet while saving rather than while exporting. See [payload_too_large](/problems/payload_too_large). + +<Note> + Saving an export straight to a cloud drive is marked in the sheet as a next-version connector. Until then, download the file and put it where you want it. +</Note> + +## Related + +- [Generate and edit](/design/editor) - the editor header where Export lives. +- [Versions](/design/versions) - the numbered history every save leaves behind. +- [Design canvases](/design/canvases) - canvases, thumbnails, and their counts. +- [Design troubleshooting](/design/troubleshooting) - a refused image or a canvas that will not save. diff --git a/design/index.mdx b/design/index.mdx index 1e48e32..5501197 100644 --- a/design/index.mdx +++ b/design/index.mdx @@ -1,68 +1,92 @@ --- title: "Cortex Design" -description: "Persistable canvases hosted from Chat or Code and edited in the Design desktop app. Frames, notes, options, and a Library of components, pages, and tokens." -image: "/images/banners/design.png" -keywords: ["canvas", "board", "UI design", "mockups"] +description: "Boards of frames and notes, hosted from a Chat thread or a Code session and edited in the Cortex Design desktop app." +icon: "pen-ruler" --- -Cortex Design is where visual work lives. A canvas is a board of frames, notes, and options that you host from a Chat conversation or a Code session and then open in the **Design desktop app** to work on. There is no Design mode in the web shell: the browser creates and lists canvases, the desktop app is where you edit them. +Cortex Design is where visual work lives. The unit of work is a **design canvas**: a board that holds frames, notes, images and pieces you reuse from your Design library. A canvas is created from, and stays linked to, one thread, either a Cortex Chat conversation or a Cortex Code session. Ask Cortex for a layout in that thread and it draws frames on the canvas beside it. -<CardGroup cols={3}> - <Card title="Canvases" icon="layout-template" href="/design/canvases"> - Frames, notes, options, and the host binding to Chat or Code. Default title Untitled canvas. +Design has exactly two surfaces. In the web app, a **CANVASES** rail sits beside a Chat thread or a Code session and lists the canvases that thread produced. The working editor is the **Cortex Design** desktop app, a separate window with its own gallery, editor, library and settings. This page is the map of the whole area. + +## Explore Design + +<CardGroup cols={2}> + <Card title="Design quickstart" icon="rocket" href="/design/quickstart"> + From an empty gallery to a saved version and an export, in a few minutes. + </Card> + <Card title="Design canvases" icon="object-group" href="/design/canvases"> + What a canvas holds, its host thread, the rail, the gallery, renaming and deleting. + </Card> + <Card title="Generate and edit" icon="wand-magic-sparkles" href="/design/editor"> + Generate options, pick one, ask for a change on a frame, retry an option that failed. + </Card> + <Card title="Versions" icon="clock-rotate-left" href="/design/versions"> + Every save is a version. View an older one, or restore it as a new version. </Card> - <Card title="Design desktop" icon="monitor" href="/design/desktop"> - Install the working UI, open a board, edit frames and notes. + <Card title="Design library" icon="swatchbook" href="/design/library"> + Components, tokens and pages you reuse across canvases, shared by your whole account. </Card> - <Card title="Library" icon="library" href="/design/library"> - Components, pages, and tokens you reuse across canvases. Thumbnails are uploaded. + <Card title="Export a design" icon="file-export" href="/design/export"> + A rendered PNG and the canvas document as JSON. SVG and PDF are planned. </Card> - <Card title="Troubleshooting" icon="life-buoy" href="/design/troubleshooting"> - Where a canvas lives, why the browser will not edit it, and a board that is not listed. + <Card title="Bot jobs" icon="robot" href="/design/bot-jobs"> + Handing a design brief to a Cortex Bot is planned. It is not available yet. + </Card> + <Card title="Design connectors" icon="plug" href="/design/plugins"> + The Plugins page in the Design window, and which connectors reach Design. + </Card> + <Card title="Design desktop app" icon="desktop" href="/design/desktop"> + What the window holds, its sidebar, and why there is nothing to install yet. + </Card> + <Card title="Design settings" icon="gear" href="/design/settings"> + General, Models, and Data and privacy, inside the Design window. + </Card> + <Card title="Design troubleshooting" icon="life-ring" href="/design/troubleshooting"> + Signed out, a canvas that is not available, the canvas quota, an option that failed. </Card> </CardGroup> -## The shape of the product +## Where Design lives + +<Tabs> + <Tab title="In the web app"> + A **CANVASES** rail is drawn beside an open Chat thread or Code session. It lists only the canvases that belong to the thread you are looking at, with each row's title, host, time and artifact counts, and a status pill of **Idle**, **In flight**, **Ready** or **Failed**. -| Fact | What it means | + The rail is a right-hand column on a wide window, and a collapsed strip under the pane on a narrow one, so the transcript keeps its width until you ask for the rail. From a row you can choose **Open in Design** when the app can be reached, or **Copy reference** to copy the canvas id and paste it into the Design window. + + There is no Design page in the browser, and no Design entry beside Chat, Code and Bot. That is the design of the product, not a gap: the rail creates and lists canvases, and the desktop app edits them. + </Tab> + <Tab title="In the desktop app"> + The **Cortex Design** window opens on **Designs**, your gallery of canvases. Its sidebar also carries **Library**, **Plugins** and **Bot jobs**, a **Settings** control, a **New design** button and a search field. + + Inside a canvas you get the editor: the board itself with a small toolbar, a thread rail where you ask for changes, a **Versions** rail, and **Export**. The window is Design only, with no Chat or Code switcher in it. + </Tab> +</Tabs> + +## How it fits with the other products + +| Product | How it meets Design | | --- | --- | -| **Hosted from Chat or Code** | Both products have design tools that create and write to a canvas. Bot does not. | -| **Edited on desktop** | The working UI is a separate desktop app. There is no `/design` route in the web app and no Design segment on the Chat · Code · Bot switcher. | -| **Private to your account** | Sign in first. Another account's canvases are not visible. | -| **Not a Chat sidecar** | A Chat canvas is a document beside a conversation. A Design canvas is a board of frames. Different objects. | - -## Start from Chat or Code - -<Steps> - <Step title="Sign in"> - Canvases are member objects. - </Step> - <Step title="Host a canvas"> - Ask Chat — *lay these three screens out on a canvas* — or ask a Code session to draw the architecture. The design tools create the board, titled **Untitled canvas**, and write frames to it. - </Step> - <Step title="Open it on desktop"> - Install the [Design desktop app](/design/desktop), sign in, and open the board. Edit frames, notes, and the Library drawer there. - </Step> -</Steps> - -## Design and the other products - -| Object | Product | What it is | -| --- | --- | --- | -| **Design canvas** | Design | A board of frames and notes, edited on desktop | -| [Chat canvas](/chat/canvases) | Chat | A document beside one conversation | -| [Plan](/chat/plans) | Chat | A task list | -| Code file | Code | A file inside a session's guest | - -Chat and Code can host a Design canvas through their design tools; Bot does not receive those tools. A [Design library](/design/library) item and a file in Chat's [Library](/chat/library) are different objects that share a word. +| [Cortex Chat](/chat) | Ask for a design in a conversation. Cortex creates a canvas bound to that conversation and draws frames on it. | +| [Cortex Code](/code) | The same, from a Code session. A mode that only answers or only plans cannot write a canvas, so use a mode that can act. See [Ask, Plan, Agent](/code/interactions). | +| [Cortex Bot](/bot) | A bot cannot open or change a design canvas today. See [Bot jobs](/design/bot-jobs). | -## Related +A canvas's host is Chat or Code, never both, and you can move that binding later. Deleting the thread a canvas came from does not delete the canvas: it only leaves the canvas with no thread. -- [Downloads](/getting-started/downloads) — every desktop app and the CLI in one place. -- [Security and privacy](/security/overview) — what Cortex stores and where your work runs. +Two nearby things share a word with Design and are separate objects. A [Chat canvas](/chat/canvases) is a markdown document written beside a conversation, not a board of frames. The [Design library](/design/library) is a set of design building blocks, while the [Chat Library](/chat/library) is a file store. [Design canvases](/design/canvases) has a table that keeps them apart. -## Next +## What is not available yet + +<Note> + Cortex Design is honest about its edges. Handing a design to a Bot is planned and does not work today. SVG and PDF export are planned; PNG and JSON ship. There is no comment surface and no publish or share surface: a canvas is private to your account, and someone else's canvas simply answers as not available. Numeric tweaking of a generated frame is also planned. +</Note> + +An account can keep up to **200 design canvases**. That is the only cap on how many designs you can have. + +## Related -1. [Canvases](/design/canvases) — what lives on a board and how it is hosted. -2. [Design desktop](/design/desktop) — install the app and open your first canvas. -3. [Design library](/design/library) — components, pages, and tokens. +- [Design quickstart](/design/quickstart) - draw, save and export your first canvas. +- [Design canvases](/design/canvases) - the board, its host thread, and the gallery. +- [Generate and edit](/design/editor) - the editor, option by option. +- [Design desktop app](/design/desktop) - get the window that does the editing. +- [Ways to run Cortex](/getting-started/downloads) - every application in one place. diff --git a/design/library.mdx b/design/library.mdx index 11a1e5f..eecdfd8 100644 --- a/design/library.mdx +++ b/design/library.mdx @@ -1,53 +1,85 @@ --- title: "Design library" -description: "Components, pages, and tokens you reuse across canvases. Thumbnails are uploaded, not rendered on this site. Not the same object as Chat's file Library." -keywords: ["components", "tokens", "assets", "design system"] +description: "The account-level set of components, pages, and tokens you reuse across every design canvas, and how it differs from the Chat Library." +icon: "swatchbook" --- -The Design library holds the reusable pieces of your visual work: **components** you place on frames, **pages** you build from them, and **tokens** — colours, spacing, type — that keep everything consistent. It lives in the Library drawer of a canvas in the Design desktop app and belongs to your signed-in account. +The Design library holds the reusable pieces of your visual work: **components** you drop onto a frame, **pages** built out of them, and **tokens**, the colour, type, and radius values that keep everything looking like one product. It belongs to your Cortex account rather than to any single canvas, so an item you add once is available on every design you open. -## Add an item +This page covers the three kinds of item the library holds, how to find and place them in the Design desktop app, how thumbnails work, and why the Design library is a different thing from the Library in Cortex Chat. The library is edited in the Design desktop app; the web app does not draw it. + +## What the library holds + +A library item is exactly one of three kinds. There is no fourth. + +| Kind | What it is | Where you use it | +| --- | --- | --- | +| **Component** | A reusable piece, made of parts, that you place on a frame | Frames on any of your canvases | +| **Page** | A screen assembled from components | The canvas you are working on | +| **Token** | A named value, such as a colour, a type family, or a corner radius | Components and pages that reference it | + +Tokens are the reason two frames can look like the same product. You maintain the values; the components that reference them follow. Each item also carries a theme, which is **light**, **dark**, or **both**, so a component built for a dark surface is not offered where it does not belong. + +Items are named by you, up to 200 characters, and can be filed under a group name of up to 128 characters. The names you give library items are encrypted at rest. + +## Open the library <Steps> - <Step title="Open a canvas in the Design desktop app"> - See [Design desktop](/design/desktop). + <Step title="Open Library in the Design desktop app"> + It is a row in the sidebar. From inside the editor you can also use the **Library** button on the canvas overlay, which keeps the canvas in view. </Step> - <Step title="Create a component, page, or token"> - From the Library drawer. + <Step title="Pick a tab"> + The library screen is split into **Components**, **Tokens**, and **Pages**, each showing how many items it holds. The header repeats the three counts for the whole library. </Step> - <Step title="Add a thumbnail when you have one"> - Thumbnails are **uploaded**. Nothing on this site rasterises them for you. + <Step title="Search"> + **Search components, tokens** filters the list by name. + </Step> + <Step title="Place a component"> + Drag it from the library onto a frame to insert it. + </Step> + <Step title="Refresh from your account"> + **Sync** pulls the library again, which is what you want after adding items from another machine. </Step> </Steps> -## What each kind of item is for +Each item shows its name, its own identifier in the shape `dli_...`, and a line counting the canvases it is used in. Components are presented as a read-only mirror of your account's components: you place them, you do not edit the source from the canvas. -| Item | What it is | Reused by | -| --- | --- | --- | -| **Component** | A piece you place on a frame | Frames on any of your canvases | -| **Page** | A screen built from components | The board you are working on | -| **Token** | A colour, spacing, or type value | Components and pages that reference it | +<Note> + The app's library also lists saved design files under a fourth tab. Those are files, not library items, and they are not one of the three kinds above. +</Note> + +## Thumbnails -Tokens are the reason two frames can look like one product: change the value once and the components that reference it follow. They are values you maintain, not a theme the app picks for you. +An item can carry a thumbnail, and a thumbnail is a picture you upload rather than a preview the app renders for you. Two rules apply, the same as for images placed on a canvas: -## Two libraries +- A thumbnail must be a raster image. `A library thumbnail must be an image.` if it is not. +- `SVG is not stored as a Design asset.` Convert the artwork to PNG before uploading it as a thumbnail. + +An uploaded picture is stored once however many places it appears, so reusing the same thumbnail costs nothing extra. + +## Two libraries, same word | | Design library | [Chat Library](/chat/library) | | --- | --- | --- | -| Holds | Components, pages, tokens | Files you uploaded and files the assistant produced | -| Lives in | The Library drawer of a canvas, on desktop | **Artifacts** in the web app sidebar | -| Used by | Frames on a Design canvas | Chat turns and projects | +| Holds | Components, pages, and tokens | Files you uploaded and files Cortex produced | +| Lives in | The Design desktop app | Cortex Chat, in the web app | +| Used by | Frames on a design canvas | Chat turns and projects | + +They share no storage and no route. An item in one never shows up in the other. -Same word, different objects. Items in one do not appear in the other. +## Access and limits -## Who can use it +The library needs a signed-in Cortex account, like every other Design surface. A signed-out visitor is refused with `Design canvases need an account. Sign in to keep your work.` See [entitlement_required](/problems/entitlement_required). Another account's items are never listed to you. -Library items are member objects, like the canvases they sit on: a guest cannot create one, and another account's items are never listed. See [Accounts](/getting-started/accounts). +If a kind, a name, or a theme is rejected, the message says which: `A library item is a component, a page, or a token.`, `A library item needs a name of at most 200 characters.`, `A library item theme is light, dark, or both.`, or `A library group name is at most 128 characters.` -The drawer is on the desktop only. The web app lists canvases but has no Library drawer and no `/design` route — see [Design desktop](/design/desktop). +<Note> + A component you place on a frame is not yet linked back to its library item, so editing the item later does not update copies already on a canvas. That link is planned rather than available. +</Note> ## Related -- [Canvases](/design/canvases) — where components are placed. -- [Design desktop](/design/desktop) -- [Design troubleshooting](/design/troubleshooting) — a Library item that is not where you expected. +- [Design canvases](/design/canvases) - the boards you place library items on. +- [Generate and edit](/design/editor) - the editor, and the Library button on the canvas. +- [Chat Library](/chat/library) - the separate file store in Cortex Chat. +- [Design troubleshooting](/design/troubleshooting) - an item that is not where you expected it. diff --git a/design/plugins.mdx b/design/plugins.mdx new file mode 100644 index 0000000..6be0be2 --- /dev/null +++ b/design/plugins.mdx @@ -0,0 +1,83 @@ +--- +title: "Design connectors" +sidebarTitle: "Connectors" +description: "The Plugins page in the Cortex Design window: browsing the connector catalogue, connecting an app, and reconnecting one whose access expired." +icon: "plug" +--- + +A **connector** hands Cortex access to an app you already use, so it can read your data and act on it. Cortex Design does not keep a catalogue of its own. It shows the same connectors as the rest of Cortex, on the sidebar row named **Plugins**, and the screen that row opens is headed **Connectors**. The row carries a meta line counting how many you have connected. + +This page covers where connectors live in the Design window, how to find one, what each card on the page is telling you, how to connect an app, and what to do when a connection stops working. Which connectors exist, and how their tools behave in a conversation, belongs to [Connectors](/chat/plugins) rather than here. + +## Where connectors live in the Design window + +Open **Plugins** in the sidebar. The page states its own purpose at the top: `Give Cortex access to your tools so it can read your data and act on it. You stay connected at the provider: Cortex never sees your passwords.` A pill beside the heading repeats the connected count. + +There is no second place to configure this. The **Integrations** pane in [Design settings](/design/settings) holds a single line saying that connectors live on the Plugins page, and an **Open Plugins** button that takes you there. + +## Find a connector + +| Control | What it does | +| --- | --- | +| **Search connectors** | Filters the catalogue by name. `⌘ K` puts the cursor in the field. | +| Chips **Discover**, **All**, **Connected** | Switch between a curated view, everything, and only the apps you have already set up. | +| Category menu | **All categories**, **Email & calendar**, **Files**, **Productivity**, **Communication**, **Developer** and **CRM**. | +| **Popular** and **New** sections | The default browse view. Each has a **Show all** control and a pager for moving through the rest. | + +If a search matches nothing, the page says it has no connector under that name and offers **See all connectors** to clear the filter, or **Request a connector** to tell Cortex what is missing. + +## What a card tells you + +Each card carries the app's name and a set of markers. Read them before you connect anything: + +| On the card | What it means | +| --- | --- | +| Surface chips **Chat**, **Code**, **Bot**, **Design** | Where this connector's tools can be used. Design is one of the surfaces a connector can reach, and a connector without a Design chip will not be available on a canvas. | +| **Verified** badge | Cortex has reviewed this connector. | +| **Soon** chip | The connector is announced but not connectable yet. Use **Notify me** on the card to be told when it lands. | +| **Reconnect required** chip, with a **Reconnect** button | The connection exists but its access has lapsed. See below. | +| **Not on your plan** | The connector is locked for your account and cannot be connected from here. | + +<Note> + Which connectors your account can use is a property of your plan, not of Cortex Design, and the Design window only reflects the answer. See [Plans](/getting-started/plans) for what is included, and [Connectors](/chat/plugins) for the catalogue itself. +</Note> + +## Connect an app + +<Steps> + <Step title="Open Plugins and find the app"> + Search by name, or browse a category. A card that offers a connect control is one your account can use. + </Step> + <Step title="Choose the connect control on the card"> + You authorise at the provider, in its own sign-in screen. Cortex never receives your password, and you can withdraw the access at the provider as well as here. + </Step> + <Step title="Or paste a key, for a connector that uses one"> + Some apps use a key instead of a sign-in. The Design window asks for it in a small dialog: paste the value into the **API key** field and choose **Continue**. The hint beside the field says the key comes from the provider and is checked before it is saved, so a bad key is refused there and then rather than failing later. + + The same dialog has an **Available in** section listing the surfaces the connector reaches, and the dialog states what happens to the value you paste: `Cortex stores the key sealed and removes it the moment you disconnect.` + </Step> + <Step title="Check the count"> + The **Plugins** row in the sidebar and the pill on the page both count what is connected, so a successful connection is visible without reopening the card. + </Step> +</Steps> + +## When a connector stops working + +Access granted at a provider does not last forever. Two things tell you it has lapsed: + +- The card gains a **Reconnect required** chip and a **Reconnect** button. Choosing it takes you back through the same authorisation. +- A message appears saying that the connector's authorisation expired, with **Reconnect** and **Dismiss**. It also names the work that is paused until you reconnect, so you are not left guessing which job stopped. + +Nothing you have already made is affected by a lapsed connection. Your canvases, versions and library are Cortex's own and do not depend on any connector. + +## When the page will not load + +If the Design window cannot reach Cortex, the page shows `Couldn't load connectors` and `You seem to be offline. Your existing connections stay active.`, with a **Retry** button. That second sentence is the important one: an unreachable catalogue does not disconnect anything. Retry once the connection is back. See [Design troubleshooting](/design/troubleshooting) for the rest of the Design window's offline behaviour. + +## Related + +- [Connectors](/chat/plugins) - the catalogue itself, and how a connector's tools behave in a conversation. +- [Connected apps and secrets](/bot/plugins) - assigning a connected app to one bot. +- [Design settings](/design/settings) - the panes beside Integrations, and what each one changes. +- [Design troubleshooting](/design/troubleshooting) - what a refusal or a failure in the Design window means. +- [Plans](/getting-started/plans) - what your account includes. diff --git a/design/quickstart.mdx b/design/quickstart.mdx new file mode 100644 index 0000000..a8983ee --- /dev/null +++ b/design/quickstart.mdx @@ -0,0 +1,94 @@ +--- +title: "Design quickstart" +description: "Open the Cortex Design app, create your first canvas, generate options, pick one, save a version and export it." +icon: "rocket" +--- + +This page takes you from an empty gallery to a saved version and a file on your machine. You need a Cortex account, and the editing itself happens in the **Cortex Design** window rather than in a browser tab. That window is not published yet, so read the steps below as what the editor does once you are in it. The last section starts a canvas from a conversation instead, which is the part the web app gives you today. + +Plan for under ten minutes. The slowest part is Cortex drawing your first frames, and you can watch that happen on the canvas. + +<Steps> + <Step title="Know where the editor lives"> + The editor is a separate application, not a page in the browser, and there is nothing to download for it yet: [Ways to run Cortex](/getting-started/downloads) records that the Design window has no installer, and no browser editor stands in for it. What the web app gives you is the **CANVASES** rail, which asks for a design, then creates and lists canvases. [Design desktop app](/design/desktop) describes the window itself. + + The window is titled **Cortex Design**, and its sidebar shows **Designs**, **Library**, **Plugins** and **Bot jobs**, with no Chat or Code switcher. + </Step> + + <Step title="Design needs an account"> + Design canvases belong to an account, and every Design surface refuses a signed-out visitor rather than drawing a locked panel. In the window that refusal is a full-window message saying that Cortex Design is part of your Cortex account, offering **Sign in** and **Create an account**; on the web the canvases rail simply does not render. The window's own sign-in is not finished either, which is the other half of why there is nothing to install yet. See [Accounts](/getting-started/accounts). + </Step> + + <Step title="Create a design"> + Open **Designs** and choose **New design** (`⌘N`). The sheet asks for four things: + + - **NAME** — up to 48 characters, with a counter beside the field. + - **START FROM** — **Blank canvas**, **From a Chat or Code thread**, or **From a Library template**. + - **BRIEF** — what you want. It becomes the first message in this design's thread, so write it as a request, not a title. + - **MODEL** — the model that will draw. Leave it alone for your first run. + + Choose **Create design** (`⌘↵`). The canvas is saved with its own reference and you can rename or move it later. + </Step> + + <Step title="Watch the options arrive"> + Cortex usually answers a brief with alternatives rather than one answer. Each alternative is a frame carrying a short option letter, so you get frame **A**, frame **B**, frame **C** for the same brief. + + While it works, the editor header reads **Drawing** with a count, and each frame card shows **Drawing…** or **Queued**. The canvas state is refreshed as work lands rather than pushed to you live, so give a slow frame a moment. + </Step> + + <Step title="Pick one and ask for a change"> + Select the frame you want. The selection draws its size and an **Edit** control. + + Now use the thread rail on the right. Type into **Ask for a change on any frame…** and send (`↵`). The header switches to an editing state naming the frame the change is landing in, and the frame card shows its own progress while the change is applied. Repeat until the frame is what you wanted. + </Step> + + <Step title="Note the version you just made"> + Every save of a canvas is a new version, numbered from 1 upwards. The thread rail confirms with a line like `Saved as v7`, plus the time and the frame and note counts. + + Open **Versions** in the editor header to see them, newest first and grouped by day, with the current one marked **CURRENT**. [Versions](/design/versions) covers viewing and restoring an older one. + </Step> + + <Step title="Export the result"> + Choose **Export** in the editor header, then: + + 1. **SCOPE** — your selection, all frames, or the whole canvas. + 2. **FORMAT** — **PNG**, rendered on your own machine, or **JSON**, the canvas document itself. SVG and PDF are shown but not selectable yet. + 3. **SCALE** — `1x`, `2x` or `3x` for a PNG. + 4. **DESTINATION** — download to this machine, or copy to the clipboard. + + The sheet shows an estimate of what you are about to produce, then confirm with **Export** (`⌘E`). See [Export a design](/design/export). + </Step> +</Steps> + +## Start from a Chat thread instead + +If the design belongs to a conversation you are already having, start it there and the canvas stays linked to that thread. + +1. Open the Chat conversation, or the Code session, that the design belongs to. +2. Ask Cortex for the design in the thread. When it draws, it creates a canvas bound to that thread. You can also create an empty one with **New canvas** in the rail. +3. The canvas appears in the **CANVASES** rail beside the thread, titled **Untitled canvas** until you rename it, with its counts such as `3 frames` and `5 notes`. +4. Choose **Open in Design** to hand it to the app, or **Copy reference** to copy the canvas id and paste it into the Design window. + +<Note> + From a Code session, a mode that only answers or only plans cannot create or change a canvas. Switch to a mode that can act. See [Ask, Plan, Agent](/code/interactions). +</Note> + +## Shortcuts worth learning now + +| Shortcut | What it does | +| --- | --- | +| `⌘N` | New design | +| `⌘K` | Focus the search field | +| `⌘↵` | Confirm the sheet you are in | +| `⌘E` | Export | +| `↵` | Send the message in the editor thread | + +These are the bindings the app shows beside its own controls, and they match Cortex Chat where the two overlap. The full list is in **Settings → General**. + +## Related + +- [Design canvases](/design/canvases) - what a canvas holds, and how the gallery and the rail work. +- [Generate and edit](/design/editor) - the editor in full, including a failed option. +- [Versions](/design/versions) - view or restore an earlier save. +- [Export a design](/design/export) - formats, scopes and what is planned. +- [Design troubleshooting](/design/troubleshooting) - when something refuses. diff --git a/design/settings.mdx b/design/settings.mdx new file mode 100644 index 0000000..36260e0 --- /dev/null +++ b/design/settings.mdx @@ -0,0 +1,87 @@ +--- +title: "Design settings" +sidebarTitle: "Settings" +description: "The Settings panes inside the Cortex Design window: General, Models, and Data and privacy, and which rows are not switched on yet." +icon: "gear" +--- + +Settings in the Cortex Design window is a dialog, not a screen you navigate to. It opens over whatever you were doing, from the **Settings** control in the sidebar, and closing it puts you back on the same canvas or gallery. A **Search settings** field looks across every pane, which is usually faster than guessing which one holds the row you want. + +The panes are listed in two groups. Under **PREFERENCES** you get **General**, **Models**, **Integrations** and **Code**. Under **ACCOUNT** you get **Data & privacy** and **Plan & billing**. This page covers the three that change how Design behaves, says what the other rows point at, and ends with a list of the controls that are drawn but not switched on yet. + +## General + +| Row | What it is | +| --- | --- | +| **Email** | The address you sign in with. It is shown, not editable. | +| **Display name** | How Cortex refers to you. Type a new one and choose **Save**. | +| **Theme** | `Light`, `Dark` or `System`. The description says it plainly: this chooses how Cortex looks on this device. The choice is remembered on the machine you set it on rather than carried with your account, and the window opens light until you change it. | +| **Language** | The interface language. The row notes that model prompts stay in English regardless. | +| **Answer font** | A choice between a sans and a serif face for long answers. Marked **COMING SOON**. | +| **Keyboard shortcuts** | Not a setting but a reference list, so you can read the bindings without leaving the window. | + +The shortcut list names **New design** on `⌘ N` and **Toggle sidebar** on ``⌘ \``, and says that the bindings match Cortex Chat where the two products overlap. [Design quickstart](/design/quickstart) has the short list worth learning first. + +## Models + +This pane is about which model draws your frames, and how much thinking it does before it draws. + +- A card shows the model Cortex is serving today, marked `PREVIEW`, with a line of what it supports. +- **Default model** would set the model new work starts with. It is marked **COMING SOON**. +- **Default thinking level** offers **Low**, **Medium** and **High**, also marked **COMING SOON**. +- **Show reasoning summaries** is a toggle, also marked **COMING SOON**. + +So until those ship, the model and the thinking level are per-canvas choices rather than account defaults. You set them on the chip in the editor's thread rail, which is covered in [Generate and edit](/design/editor). + +The pane carries one banner worth reading: `Model availability depends on your plan. During peak hours new chats may fall back to a faster model.` Read it as a statement about what a plan includes rather than as a description of what will happen during your session: the editor's picker marks a model your account does not include with `Not on plan`, and today every published model is available from the Free plan up, so that marker is not one you should expect to meet. + +## Data & privacy + +This pane is the Design window's view of the same account-wide controls you get elsewhere in Cortex, so the decisions you make here are not Design-only. + +| Row | What it is | +| --- | --- | +| **Save chat history** | Would let you stop conversations being kept in your account, at the cost of losing them when you close them. Marked **SOON**. | +| **Improve the model** | Would allow a sample of your conversations to be reviewed to train future models. It is off by default, and the row states that your conversations are never used without it. Marked **SOON**. | +| **Memory** | The standing facts and preferences Cortex has picked up from you, listed one per row with a **Delete** on each. | +| **Your data** | `Export everything we hold, or delete it permanently. Deletion takes effect within 30 days.` **Export my data** is marked **SOON** here; **Delete all data** is active. | + +<Warning> + **Delete all data** is not a Design-only control. It schedules the permanent erasure of your account and everything in it, canvases included. Read [Data and privacy](/getting-started/data-and-privacy) before you use it, including how long you have to change your mind. +</Warning> + +For the two rows marked **SOON**, and for an export you need today, use the same controls in Cortex Settings in the web app. [Memory](/chat/memory) covers what Cortex remembers and how the list behaves. + +## Integrations, Code and Plan & billing + +Three rows in the dialog are pointers rather than panes of their own: + +- **Integrations** holds one line saying that connectors live on the Plugins page, and an **Open Plugins** button. See [Design connectors](/design/plugins). +- **Code** holds one line and no controls: `Code editor preferences stay in Cortex Code. This window is Design-only`. Editor preferences are set in [Cortex Code](/code/settings), and there is no Chat or Code switcher in the Design window by design. +- **Plan & billing** shows what your account is on. The account pages own that subject; see [Plans](/getting-started/plans). + +## What is not switched on yet + +Several rows are drawn with a chip that says they are not ready. Treat every one of them as unavailable rather than as a setting that failed to save: + +| Row | Pane | Chip | +| --- | --- | --- | +| Answer font | General | **COMING SOON** | +| Default model | Models | **COMING SOON** | +| Default thinking level | Models | **COMING SOON** | +| Show reasoning summaries | Models | **COMING SOON** | +| Save chat history | Data & privacy | **SOON** | +| Improve the model | Data & privacy | **SOON** | +| Export my data | Data & privacy | **SOON** | + +<Note> + Nothing in Settings changes how many designs you can keep. An account holds up to 200 design canvases, and that is the only cap on the number of designs. It is not a per-plan allowance and it does not reset on a schedule. See [Design canvases](/design/canvases). +</Note> + +## Related + +- [Design connectors](/design/plugins) - the page the Integrations row sends you to. +- [Generate and edit](/design/editor) - where the model and the thinking level are chosen today. +- [Design canvases](/design/canvases) - the 200-canvas cap and the other limits. +- [Data and privacy](/getting-started/data-and-privacy) - the account-wide version of the pane above. +- [Design troubleshooting](/design/troubleshooting) - when a Design surface refuses or fails. diff --git a/design/troubleshooting.mdx b/design/troubleshooting.mdx index 1bac438..810e896 100644 --- a/design/troubleshooting.mdx +++ b/design/troubleshooting.mdx @@ -1,60 +1,132 @@ --- title: "Design troubleshooting" -description: "Where a canvas lives, why the browser will not edit it, a Library item that is not there, and the app that is not opening." -keywords: ["errors", "problems", "fixes", "not working", "canvas missing"] +description: "What a Cortex Design refusal means: signed out, a canvas that is not available, the canvas cap, a save that clashed, an option that did not finish." +icon: "life-ring" --- -Design spans two places on purpose: the browser creates and lists a canvas, the [Design desktop app](/design/desktop) edits it. Most confusion comes from looking for the editor in the wrong one. For the rest of the app see [Troubleshooting](/getting-started/troubleshooting). +Cortex Design refuses in plain sentences rather than in codes, so the message you are looking at is usually the answer. This page lists the message or the state you see, what caused it, and what to do about it, grouped by the part of Design you were in when it happened. -## Access +One piece of orientation explains a good share of the confusion. Design has two surfaces: a **CANVASES** rail beside a Chat thread or a Code session, which lists and creates canvases, and the Cortex Design window, which edits them. There is no Design page in the browser, so if you are hunting for the editor there, that is why you cannot find it. See [Cortex Design](/design) for the map. -| What you see | Cause | Fix | +## Signing in and access + +| What you see | What it means | What to do | | --- | --- | --- | -| No canvas tools at all | You are a guest | Canvases are member objects. Sign in — see [Accounts](/getting-started/accounts) | -| A canvas that is not yours is missing | Canvases are private to the account that owns them | Expected. Another account's boards are never listed | -| **No `/design` route** in the browser | The web app has no Design mode | Create and list canvases from Chat or Code, then edit in the desktop app | +| `Design canvases need an account. Sign in to keep your work.` | You are signed out. Every Design surface refuses a visitor without an account. | Sign in, or create an account. See [entitlement_required](/problems/entitlement_required). | +| No rail at all beside a thread | Same cause. Rather than showing a locked panel, the rail draws nothing when you are signed out. | Sign in and reopen the thread. | +| A dialog headed `Cortex Design is part of your Cortex account.` | The Design window's version of the same refusal, with **Sign in** and **Create an account**. | Sign in with the account that owns the canvases. | +| A dialog headed `Your session expired` | Your sign-in lapsed while the window was open. | Choose **Sign in again**. Work you did in the window in the meantime is kept on this computer and syncs back once you are in. See [unauthenticated](/problems/unauthenticated). | +| `This canvas isn't available` | The canvas does not exist, or it belongs to another account. Cortex gives the same answer for both, so it never reveals whether a canvas exists outside your account. | Check you are signed in as the right account, or ask the owner for the reference. See [not_found](/problems/not_found). | -## The canvas +## The canvas cap -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| The board is called **Untitled canvas** | That is the default until you rename it | Rename it from the desktop app; the host binding stays | -| Frames are missing after a rename | The rename did not change which conversation hosts the board | Reopen the board — the host binding is unchanged by a rename | -| The canvas disappeared from the list | Deleting a canvas hides it from the list | There is no restore. Host a new one from [Chat](/chat/canvases) or [Code](/code) | -| Chat made a document, not a board | A [Chat canvas](/chat/canvases) is a document beside one conversation | Ask for a **Design** canvas, or open the board from the Design desktop app | +| `This account already has the maximum number of Design canvases.` | Your account already holds 200 design canvases, which is the ceiling. | Make room, then create again. See [quota_exceeded](/problems/quota_exceeded). | + +Making room needs one detail. Deleting a design **hides** it: its versions and images stay so it can come back, and a hidden canvas is still yours, so it still occupies one of the 200. If you are at the cap, permanently delete a hidden canvas rather than only hiding another one. -## The Library +<Note> + 200 canvases per account is the only cap on how many designs you can have. There is no daily allowance, no monthly allowance and no separate per-plan figure for Design, so a refusal at this point is about the total you hold, not about something resetting later. +</Note> -| What you see | Cause | Fix | +## A save that was refused + +| What you see | What it means | What to do | | --- | --- | --- | -| No Library drawer in the browser | The drawer lives on a canvas in the desktop app | Open the board in the [Design desktop app](/design/desktop) | -| A component has no thumbnail | Thumbnails are **uploaded**, not rendered | Upload one, or leave it — the item still works | -| A Chat file is not in the Design Library | They are different objects that share a word | See [two libraries](/design/library#two-libraries) | +| `This canvas was saved from another tab. Reload and try again.` | Two windows saved the canvas from the same starting version, and the second one lost. | Reload the canvas and redo the change. See [conflict](/problems/conflict). | +| `This canvas is too large to save.` | The canvas document has outgrown 8 MiB uncompressed. | Split the work across canvases, or remove content. See [payload_too_large](/problems/payload_too_large). | +| `This canvas has too many nodes.` | A canvas holds at most 8,000 pieces. | The same fix: split the board. See [validation_failed](/problems/validation_failed). | +| `A note is at most 16,384 characters.` | One note went past its length. | Shorten it, or split it into two notes. | +| `A canvas title is at most 200 characters.` | The title you typed is too long. | Shorten the title. Renaming does not affect which thread hosts the canvas. | +| `The canvas page size is invalid.` | A page was given a width or a height outside the allowed range. | Return the page to a sensible size. A new page starts at 1440 by 900. | -## The desktop app +## An image that was refused -| What you see | Cause | Fix | +| What you see | What it means | What to do | | --- | --- | --- | -| The app asks you to sign in | Canvases are member objects | Sign in with the same account as the web app | -| Your boards are not listed | The app is signed in as a different account | Sign in as the account that hosted them | -| A download is missing for your platform | Desktop builds are published per platform | Check [releases.cortex.foundation](https://releases.cortex.foundation) — see [Downloads](/getting-started/downloads) | +| `A Design asset is at most 8 MB.` | The file you placed, or the thumbnail you uploaded, is over the per-file ceiling. | Reduce the file and try again. | +| `SVG is not stored as a Design asset.` | Vector files are not accepted on a canvas. | Convert the artwork to PNG first. | +| `A thumbnail or image fill must be an image.` | The file is not a raster image at all. | Use a PNG or another raster format. | + +See [Export a design](/design/export) for the thumbnail a canvas carries and what export produces. + +## An option that did not finish + +When Cortex answers a brief with several options and one of them stops, the rest of the board is unaffected. The frame that could not finish shows **Failed** and its card explains in words why the attempt stopped. + +<Steps> + <Step title="Read the card"> + It names the option and the reason. Nothing else on the canvas is rolled back. + </Step> + <Step title="Retry just that option"> + Use the retry control on the frame card, or the matching retry in the thread. It reruns that option only. + </Step> + <Step title="Or remove the frame"> + **Remove frame** drops the failed option and keeps the rest of the canvas. + </Step> +</Steps> + +Until you do one or the other, the whole canvas reports its state as failed. That is deliberate: a failed piece outranks a piece that is still being drawn, which outranks a finished one, so the canvas tells you about the worst thing on it rather than the newest. + +<Note> + A board that looks stuck is sometimes a board between refreshes. The editor's pills use the word `Streaming` while a change lands, but Design refreshes canvas state rather than receiving a live push, so give it a moment, or reopen the canvas, before treating it as failed. +</Note> + +## When Cortex cannot be reached + +The Design window is built to say so rather than to look empty. + +| What you see | What it means | +| --- | --- | +| `Couldn't reach Cortex` | The window could not reach the service at all. | +| `Couldn't load your designs`, with **Work offline** and **Retry** | The gallery is showing your last sync rather than the live list. | +| `Couldn't reach Cortex — showing last sync` with a time | The same thing, said in the gallery header. | +| `Canvases could not be loaded.` with **Retry** | The web app's rail could not load. Retry it. | +| `Couldn't load connectors` | The connectors page could not load. Connections you already have stay active. See [Design connectors](/design/plugins). | + +While you are offline, canvases you already have open stay readable from the copy on your machine, and edits queue and sync when the connection returns. If the window will not get past this state, there is no Design-specific recovery step beyond retrying: check [Status](/reference/status) or [status.cortex.foundation](https://status.cortex.foundation) for an incident, then see [Troubleshooting](/getting-started/troubleshooting) for the guidance that applies to every Cortex application. + +## A control you cannot find + +Comments, sharing and the numeric tweak control are not available in Cortex Design today. -## Errors +<AccordionGroup> + <Accordion title="I want to leave a comment on a frame"> + There is no comment surface on a canvas, and no way to resolve or reply to one. Leave a **note** on the board instead: notes are part of the canvas, they are saved into the version history with everything else, and Cortex reads them. See [Design canvases](/design/canvases). + </Accordion> + <Accordion title="I want to share a canvas or publish a read-only link"> + Sharing is not available. A canvas is private to the account that owns it, there is no publish control, no viewer link and no access list, and someone else's canvas answers exactly as one that does not exist. To hand the work to someone, export it: a rendered PNG for a person to look at, or the canvas document as JSON. See [Export a design](/design/export). + </Accordion> + <Accordion title="I want to adjust a number on a generated frame"> + Editing a generated frame by its numbers is not available yet. Ask for the change in the editor thread instead, naming the frame, and Cortex redraws it. See [Generate and edit](/design/editor). + </Accordion> + <Accordion title="I am looking for the status of a design handed to a bot"> + There is no queue and no status board to look at. The **Bot jobs** row, the **Hand to Bot** button in the editor header and the **Hand to a Bot** sheet are drawn, but nothing runs behind them, and a Cortex Bot cannot open or change a design canvas today. See [Bot jobs](/design/bot-jobs). + </Accordion> + <Accordion title="A file from Cortex Chat is not in my Design library"> + They are separate stores that share a word. The Design library holds components, tokens and pages you reuse on canvases; the Chat Library is a file store. See [Design library](/design/library). + </Accordion> +</AccordionGroup> -Design uses the same problem documents as the rest of Cortex: +## Error codes used by Design -| Code | Meaning | +| Code | When Design returns it | | --- | --- | -| [`unauthenticated`](/problems/unauthenticated) | You are not signed in | -| [`forbidden`](/problems/forbidden) | The action is not permitted for this account | -| [`not_found`](/problems/not_found) | The canvas or Library item no longer exists | -| [`invalid_state`](/problems/invalid_state) | The board is not in a state that allows the action | +| [entitlement_required](/problems/entitlement_required) | You are signed out. | +| [unauthenticated](/problems/unauthenticated) | Your session lapsed while you were working. | +| [not_found](/problems/not_found) | The canvas, or the library item, is not one of yours. | +| [validation_failed](/problems/validation_failed) | Something you sent was out of bounds: a title, a note, a node count, a page size. | +| [conflict](/problems/conflict) | The canvas was saved from somewhere else first. | +| [payload_too_large](/problems/payload_too_large) | The canvas document is over its size ceiling. | +| [quota_exceeded](/problems/quota_exceeded) | You already hold 200 design canvases. | -Full list: [Problem catalog](/problems). +The full catalogue is at [Problems](/problems). ## Related -- [Canvases](/design/canvases) — what lives on a board and how it is hosted. -- [Design desktop](/design/desktop) — the app that edits it. -- [Design library](/design/library) — components, pages, and tokens. -- [Troubleshooting](/getting-started/troubleshooting) — the same guidance across all products. +- [Design canvases](/design/canvases) - the limits behind most of these refusals. +- [Generate and edit](/design/editor) - options, retries and the editor's states. +- [Design settings](/design/settings) - the panes, and the rows that are not switched on yet. +- [Design connectors](/design/plugins) - a connection that lapsed or a catalogue that will not load. +- [Troubleshooting](/getting-started/troubleshooting) - the same guidance across every Cortex application. diff --git a/design/versions.mdx b/design/versions.mdx new file mode 100644 index 0000000..6d9915c --- /dev/null +++ b/design/versions.mdx @@ -0,0 +1,83 @@ +--- +title: "Versions" +description: "Every save of a design canvas is a numbered version you can view, restore, or compare from the Versions rail in the Design desktop app." +icon: "clock-rotate-left" +--- + +Every time a design canvas is saved, Cortex Design keeps the result as a numbered version. Nothing is overwritten. Version 7 of a canvas is its seventh save, and the six saves before it are all still there to open. Versions are how you go back after a change you did not want, and how you check what a canvas looked like before a round of edits. + +This page covers how a save becomes a version, how to open the **Versions** rail in the editor, how to read an older version without changing anything, what restoring actually does, and what is worth knowing about comparing. Versions live in the Design desktop app: the canvases rail in the web app lists a canvas and its counts, but the history is in the editor. + +## How a save becomes a version + +Each save creates the next version, numbered from 1 upwards, and the canvas records which version is current. When a save lands, the thread rail beside the canvas confirms it with a line naming the new version, the time, and how many frames and notes the canvas now holds. + +You never choose how a save is stored. Cortex writes a complete snapshot of the canvas at intervals on its own, so the history stays quick to replay however many small edits sit between snapshots. + +Saving is protected against two windows fighting over the same canvas. If a second window saves starting from a version that is no longer current, that save is refused with `This canvas was saved from another tab. Reload and try again.` Reload the canvas and redo the change. See [conflict](/problems/conflict). + +## Open the Versions rail + +The editor header carries a **Versions** button with the number of saved versions on it. Opening it shows the rail: + +- Versions newest first, grouped by day under headings such as **TODAY** and **YESTERDAY**. +- Each row names the version, who saved it, and the time. +- The current version carries a **CURRENT** chip. +- The version you are reading carries a **VIEWING** chip. + +## View an older version + +<Steps> + <Step title="Open Versions in the editor header"> + The rail opens beside the canvas. + </Step> + <Step title="Select the version you want to read"> + The header pill switches to a read-only viewing state, for example **Viewing v4 · read-only**, and a banner across the canvas repeats the version and when it was saved. + </Step> + <Step title="Return to the current version"> + Choose the control that names the current version, for example **Back to v7**. + </Step> +</Steps> + +Viewing is read-only in the literal sense: you are reading an older version of the canvas, and nothing you do while the banner is up changes the current one. + +## Restore an older version + +Restoring does not rewind the canvas and does not throw away the work you did since. It takes the older version and saves it again as a brand new version at the top of the list. + +<Steps> + <Step title="Select the older version in the rail"> + Its row is highlighted and the canvas shows it read-only. + </Step> + <Step title="Choose the restore control"> + It names the version you picked, for example **Restore v4**. + </Step> + <Step title="Carry on from the new version"> + The restored content becomes the newest version and the current one. Its row is labelled as restored from the version it came from. + </Step> +</Steps> + +<Note> + Nothing is deleted by a restore. The version you were on before stays in the list, in its place, and you can restore that one in turn if you change your mind. +</Note> + +## Compare with the current version + +Beside each older version the rail offers a compare control, which names the current version, for example **Compare with v7**, and sets that version against the one you are working on. What the comparison itself draws is not documented, so expect the control before you expect a particular view. + +## What versions do not do + +- A single version cannot be removed from the list on its own. The list only grows, including when you restore. +- There is no clock running against your history. As long as you keep the canvas, its earlier versions stay with it. +- Versions belong to one canvas. They are not shared between canvases, and a library item has no version list of its own. + +<Note> + Deleting a design hides it rather than erasing it. Its versions and images stay with it and it can come back, and the Design desktop app offers an undo for ten seconds immediately after the delete. See [Design canvases](/design/canvases). +</Note> + +## Related + +- [Generate and edit](/design/editor) - where saves happen and where the Versions button lives. +- [Design canvases](/design/canvases) - what a canvas is, and what deleting one does. +- [Export a design](/design/export) - take a version out as a file. +- [Design troubleshooting](/design/troubleshooting) - a save that was refused, or a canvas that will not open. diff --git a/docs.json b/docs.json index 2f3b598..6679835 100644 --- a/docs.json +++ b/docs.json @@ -1,51 +1,528 @@ { "$schema": "https://mintlify.com/docs.json", + "theme": "mint", "name": "Cortex Docs", - "theme": "willow", - "description": "Product docs for Cortex Chat, Code, Bot, Design, and the Cortex CLI. Platform API lives elsewhere.", + "description": "Documentation for Cortex Chat, Cortex Code, Cortex Bot, Cortex Design, Cortex Security, and the Cortex CLI.", "colors": { "primary": "#1F4945", "light": "#8AC5B9", "dark": "#163834" }, - "fonts": { - "family": "Inter", - "heading": { - "family": "Inter" - }, - "body": { - "family": "Inter" - } + "favicon": "/favicon.svg", + "logo": { + "light": "/logo/wordmark-light.svg", + "dark": "/logo/wordmark-dark.svg", + "href": "https://docs.cortex.foundation" }, "appearance": { "default": "system" }, - "background": { - "color": { - "light": "#FAF8F4", - "dark": "#211F1C" + "navigation": { + "tabs": [ + { + "tab": "Get started", + "icon": "rocket", + "groups": [ + { + "group": "Welcome", + "icon": "star", + "pages": [ + "index", + "getting-started/quickstart", + "getting-started/what-is-cortex", + "getting-started/choose-a-product" + ] + }, + { + "group": "Your account", + "icon": "user", + "pages": [ + "getting-started/accounts", + "getting-started/two-factor", + "getting-started/plans", + "getting-started/settings", + "getting-started/data-and-privacy", + "getting-started/notifications", + "getting-started/language" + ] + }, + { + "group": "Apps and downloads", + "icon": "download", + "pages": [ + "getting-started/downloads", + "getting-started/desktop" + ] + }, + { + "group": "Help", + "icon": "life-ring", + "pages": [ + "getting-started/troubleshooting", + "getting-started/keyboard-shortcuts", + "getting-started/report-a-bug", + "getting-started/faq", + "getting-started/glossary" + ] + } + ] + }, + { + "tab": "Chat", + "icon": "comments", + "groups": [ + { + "group": "Overview", + "icon": "compass", + "pages": [ + "chat/index", + "chat/quickstart", + "chat/how-it-works" + ] + }, + { + "group": "Conversations", + "icon": "message", + "pages": [ + "chat/conversations", + "chat/models", + "chat/attachments", + "chat/streaming", + "chat/voice", + "chat/canvases", + "chat/document-export" + ] + }, + { + "group": "Organize your work", + "icon": "folder-open", + "pages": [ + "chat/projects", + "chat/library", + "chat/library-sharing", + "chat/memory", + "chat/plans", + "chat/scheduled-tasks" + ] + }, + { + "group": "Research and creation", + "icon": "wand-magic-sparkles", + "pages": [ + "chat/tools", + "chat/deep-research", + "chat/image-generation", + "chat/origin-check", + "chat/data", + "chat/skills" + ] + }, + { + "group": "Connected apps", + "icon": "plug", + "pages": [ + "chat/plugins", + "chat/mcp-servers", + "chat/page-tools" + ] + }, + { + "group": "Reference", + "icon": "book", + "pages": [ + "chat/sharing", + "chat/troubleshooting" + ] + } + ] + }, + { + "tab": "Code", + "icon": "code", + "groups": [ + { + "group": "Overview", + "icon": "compass", + "pages": [ + "code/index", + "code/quickstart", + "code/how-it-works" + ] + }, + { + "group": "Sessions", + "icon": "list-check", + "pages": [ + "code/sessions", + "code/interactions", + "code/approvals", + "code/changes", + "code/tickets" + ] + }, + { + "group": "Where code runs", + "icon": "server", + "pages": [ + "code/runtimes", + "code/environments", + "code/machines", + "code/ssh-hosts", + "code/desktop" + ] + }, + { + "group": "Repositories", + "icon": "code-branch", + "pages": [ + "code/github", + "code/repositories" + ] + }, + { + "group": "Automate and monitor", + "icon": "bolt", + "pages": [ + "code/automations", + "code/notifications", + "code/usage" + ] + }, + { + "group": "Configure", + "icon": "gear", + "pages": [ + "code/settings", + "code/integrations" + ] + }, + { + "group": "Reference", + "icon": "book", + "pages": [ + "code/cli", + "code/security", + "code/troubleshooting" + ] + } + ] + }, + { + "tab": "Bot", + "icon": "robot", + "groups": [ + { + "group": "Overview", + "icon": "compass", + "pages": [ + "bot/index", + "bot/quickstart", + "bot/how-it-works" + ] + }, + { + "group": "Your bots", + "icon": "user-astronaut", + "pages": [ + "bot/create-a-bot", + "bot/conversations", + "bot/computer", + "bot/tools", + "bot/approvals", + "bot/memory", + "bot/skills", + "bot/routines", + "bot/tasks", + "bot/plugins", + "bot/inbox" + ] + }, + { + "group": "Collaborate", + "icon": "users", + "pages": [ + "bot/rooms", + "bot/sharing", + "bot/teach" + ] + }, + { + "group": "Apps", + "icon": "desktop", + "pages": [ + "bot/desktop" + ] + }, + { + "group": "Reference", + "icon": "book", + "pages": [ + "bot/troubleshooting" + ] + } + ] + }, + { + "tab": "CLI", + "icon": "terminal", + "groups": [ + { + "group": "Get started", + "icon": "rocket", + "pages": [ + "cli/index", + "cli/install", + "cli/sign-in", + "cli/quickstart" + ] + }, + { + "group": "Use the CLI", + "icon": "keyboard", + "pages": [ + "cli/tui", + "cli/modes-and-permissions", + "cli/plan-mode", + "cli/sessions", + "cli/goal", + "cli/slash-commands", + "cli/keyboard", + "cli/tools", + "cli/hosts", + "cli/editor" + ] + }, + { + "group": "Automate", + "icon": "gears", + "pages": [ + "cli/headless", + "cli/ci" + ] + }, + { + "group": "Configure", + "icon": "sliders", + "pages": [ + "cli/configuration", + "cli/environment-variables", + "cli/data-locations", + "cli/policy" + ] + }, + { + "group": "Extend", + "icon": "puzzle-piece", + "pages": [ + "cli/mcp", + "cli/skills", + "cli/agents", + "cli/hooks", + "cli/plugins", + "cli/themes" + ] + }, + { + "group": "Reference", + "icon": "book", + "pages": [ + "cli/reference", + "cli/troubleshooting" + ] + } + ] + }, + { + "tab": "Design", + "icon": "pen-ruler", + "groups": [ + { + "group": "Overview", + "icon": "compass", + "pages": [ + "design/index", + "design/quickstart" + ] + }, + { + "group": "Work with designs", + "icon": "object-group", + "pages": [ + "design/canvases", + "design/editor", + "design/versions", + "design/library", + "design/export", + "design/bot-jobs", + "design/plugins" + ] + }, + { + "group": "App and settings", + "icon": "desktop", + "pages": [ + "design/desktop", + "design/settings", + "design/troubleshooting" + ] + } + ] + }, + { + "tab": "Security", + "icon": "shield-halved", + "groups": [ + { + "group": "Overview", + "icon": "compass", + "pages": [ + "security/index", + "security/quickstart", + "security/how-a-review-works" + ] + }, + { + "group": "Reviews and scans", + "icon": "magnifying-glass", + "pages": [ + "security/checks", + "security/review-policy", + "security/scans", + "security/agent" + ] + }, + { + "group": "Configure", + "icon": "gear", + "pages": [ + "security/repositories", + "security/troubleshooting" + ] + } + ] + }, + { + "tab": "Reference", + "icon": "book-open", + "groups": [ + { + "group": "Errors", + "icon": "triangle-exclamation", + "pages": [ + "reference/errors", + { + "group": "Problem codes", + "icon": "list", + "root": "problems/index", + "expanded": false, + "pages": [ + "problems/validation_failed", + "problems/bad_request", + "problems/idempotency_key_reuse", + "problems/payload_too_large", + "problems/unsupported_media_type", + "problems/unauthenticated", + "problems/invalid_credential", + "problems/forbidden", + "problems/entitlement_required", + "problems/not_found", + "problems/conflict", + "problems/gone", + "problems/invalid_state", + "problems/quota_exceeded", + "problems/rate_limited", + "problems/concurrency_limit_reached", + "problems/safety_intervention", + "problems/content_policy", + "problems/jurisdiction_restricted", + "problems/internal", + "problems/upstream_failure", + "problems/upstream_timeout", + "problems/service_unavailable", + "problems/no_capacity" + ] + } + ] + }, + { + "group": "Platform", + "icon": "layer-group", + "pages": [ + "reference/models", + "reference/limits", + "reference/security-and-privacy", + "reference/status", + "reference/platform-api" + ] + }, + { + "group": "Bounty program", + "icon": "coins", + "pages": [ + "bounty/index", + "bounty/pair-a-hotkey", + "bounty/report", + "bounty/scoring", + "bounty/public-api" + ] + }, + { + "group": "Updates", + "icon": "clock-rotate-left", + "pages": [ + "changelog" + ] + } + ] + } + ], + "global": { + "anchors": [ + { + "anchor": "Changelog", + "href": "/changelog", + "icon": "clock-rotate-left" + }, + { + "anchor": "System status", + "href": "https://status.cortex.foundation", + "icon": "signal" + }, + { + "anchor": "cortex.foundation", + "href": "https://cortex.foundation", + "icon": "globe" + } + ] } }, - "favicon": "/logo/light.svg", - "logo": { - "light": "/logo/banner-light.png", - "dark": "/logo/banner-dark.png", - "href": "https://docs.cortex.foundation" - }, "navbar": { "links": [ { - "label": "Home", - "href": "/" + "label": "Website", + "href": "https://cortex.foundation" }, { - "label": "Documentation", - "href": "/getting-started/quickstart" + "label": "Status", + "href": "https://status.cortex.foundation" } + ], + "primary": { + "type": "button", + "label": "Open Cortex", + "href": "https://cortex.foundation" + } + }, + "contextual": { + "options": [ + "copy", + "view", + "mcp" ] }, "footer": { "socials": { + "github": "https://github.com/CortexLM", "website": "https://cortex.foundation" }, "links": [ @@ -71,6 +548,10 @@ { "label": "Design", "href": "/design" + }, + { + "label": "Security", + "href": "/security" } ] }, @@ -78,11 +559,11 @@ "header": "Resources", "items": [ { - "label": "Get started", + "label": "Quickstart", "href": "/getting-started/quickstart" }, { - "label": "Downloads", + "label": "Ways to run Cortex", "href": "/getting-started/downloads" }, { @@ -90,12 +571,12 @@ "href": "/getting-started/troubleshooting" }, { - "label": "Changelog", - "href": "/changelog" + "label": "Error codes", + "href": "/problems" }, { - "label": "System status", - "href": "/status" + "label": "Changelog", + "href": "/changelog" } ] }, @@ -107,7 +588,7 @@ "href": "https://cortex.foundation" }, { - "label": "Status", + "label": "System status", "href": "https://status.cortex.foundation" }, { @@ -123,19 +604,18 @@ ] }, "search": { - "prompt": "Search docs..." + "prompt": "Search the Cortex docs..." }, "errors": { "404": { "redirect": false, "title": "Page not found", - "description": "That path is not in Cortex Docs. Try [Get started](/getting-started/quickstart), [Chat](/chat), [Code](/code), [Bot](/bot), [CLI](/cli), or [Design](/design). If a product message sent you here, the [problem catalog](/problems) explains it. The inference Platform API is not documented here." + "description": "That path is not in the Cortex docs. Try the [Quickstart](/getting-started/quickstart), or pick a product: [Chat](/chat), [Code](/code), [Bot](/bot), [CLI](/cli), [Design](/design), [Security](/security). If an error message sent you here, the [problem catalog](/problems) explains it." } }, "seo": { "metatags": { - "og:site_name": "Cortex Docs", - "og:image": "/images/banners/getting-started.png" + "og:site_name": "Cortex Docs" }, "organization": { "name": "Cortex", @@ -144,260 +624,120 @@ }, "redirects": [ { - "source": "/chat/overview", + "source": "/api/overview", + "destination": "/reference/errors" + }, + { + "source": "/api/errors", + "destination": "/reference/errors" + }, + { + "source": "/api/authentication", + "destination": "/getting-started/accounts" + }, + { + "source": "/api/oauth", + "destination": "/getting-started/accounts" + }, + { + "source": "/api/chat", "destination": "/chat" }, { - "source": "/code/overview", + "source": "/api/code", "destination": "/code" }, { - "source": "/bot/overview", + "source": "/api/bot", "destination": "/bot" }, { - "source": "/design/overview", + "source": "/api/design", "destination": "/design" }, { - "source": "/chat/conversations", - "destination": "/chat/projects" + "source": "/api/plugins", + "destination": "/chat/plugins" }, { - "source": "/chat/plugins", - "destination": "/chat/tools" + "source": "/api/streaming", + "destination": "/chat/streaming" }, { - "source": "/chat/artifacts", - "destination": "/chat/library" + "source": "/api/webhooks", + "destination": "/security" }, { - "source": "/getting-started/cli", - "destination": "/cli/install" + "source": "/security/overview", + "destination": "/reference/security-and-privacy" }, { - "source": "/getting-started/desktop-app", - "destination": "/getting-started/desktop" + "source": "/status", + "destination": "/reference/status" }, { - "source": "/code/goals", - "destination": "/cli/goal" + "source": "/platform", + "destination": "/reference/platform-api" }, { "source": "/troubleshooting", "destination": "/getting-started/troubleshooting" }, { - "source": "/api/authentication", - "destination": "/getting-started/accounts" + "source": "/getting-started/desktop-app", + "destination": "/getting-started/desktop" }, { - "source": "/api/oauth", - "destination": "/getting-started/accounts" + "source": "/getting-started/cli", + "destination": "/cli/install" }, { - "source": "/api/chat", + "source": "/chat/overview", "destination": "/chat" }, { - "source": "/api/code", + "source": "/chat/images", + "destination": "/chat/image-generation" + }, + { + "source": "/chat/conversations/overview", + "destination": "/chat/conversations" + }, + { + "source": "/chat/plugins/overview", + "destination": "/chat/plugins" + }, + { + "source": "/chat/artifacts", + "destination": "/chat/library" + }, + { + "source": "/code/overview", "destination": "/code" }, { - "source": "/api/bot", - "destination": "/bot" + "source": "/code/cloud", + "destination": "/code/runtimes" }, { - "source": "/api/design", - "destination": "/design" + "source": "/code/goals", + "destination": "/cli/goal" }, { - "source": "/api/plugins", - "destination": "/chat/tools" + "source": "/code/review", + "destination": "/security" }, { - "source": "/api/streaming", - "destination": "/chat/streaming" + "source": "/bot/overview", + "destination": "/bot" }, { - "source": "/api/webhooks", - "destination": "/code/security" + "source": "/design/overview", + "destination": "/design" + }, + { + "source": "/cli/extend", + "destination": "/cli/mcp" } - ], - "navigation": { - "groups": [ - { - "group": "Start here", - "root": "getting-started/quickstart", - "icon": "rocket", - "pages": [ - "getting-started/what-is-cortex", - "getting-started/accounts", - "getting-started/plans", - "getting-started/settings" - ] - }, - { - "group": "Downloads", - "root": "getting-started/downloads", - "icon": "download", - "pages": [ - "getting-started/desktop" - ] - }, - { - "group": "Chat", - "root": "chat/index", - "icon": "message-square", - "pages": [ - "chat/quickstart", - "chat/projects", - "chat/library", - "chat/plans", - "chat/sharing", - "chat/models", - "chat/tools", - "chat/deep-research", - "chat/images", - "chat/origin-check", - "chat/voice", - "chat/memory", - "chat/canvases", - "chat/how-it-works", - "chat/streaming", - "chat/troubleshooting" - ] - }, - { - "group": "Code", - "root": "code/index", - "icon": "code", - "pages": [ - "code/quickstart", - "code/sessions", - "code/interactions", - "code/github", - "code/security", - "code/cloud", - "code/desktop", - "code/cli", - "code/how-it-works", - "code/troubleshooting" - ] - }, - { - "group": "Bot", - "root": "bot/index", - "icon": "bot", - "pages": [ - "bot/quickstart", - "bot/computer", - "bot/tools", - "bot/approvals", - "bot/routines", - "bot/skills", - "bot/desktop", - "bot/how-it-works", - "bot/troubleshooting" - ] - }, - { - "group": "CLI", - "root": "cli/index", - "icon": "terminal", - "pages": [ - "cli/install", - "cli/sign-in", - "cli/quickstart", - "cli/tui", - "cli/slash-commands", - "cli/modes-and-permissions", - "cli/goal", - "cli/sessions", - "cli/keyboard", - "cli/headless", - "cli/configuration", - "cli/extend", - "cli/troubleshooting" - ] - }, - { - "group": "Design", - "root": "design/index", - "icon": "layout-template", - "pages": [ - "design/canvases", - "design/desktop", - "design/library", - "design/troubleshooting" - ] - }, - { - "group": "API", - "root": "api/overview", - "icon": "braces", - "pages": [ - "api/errors", - { - "group": "Problems", - "root": "problems/index", - "icon": "circle-alert", - "expanded": false, - "pages": [ - "problems/validation_failed", - "problems/bad_request", - "problems/idempotency_key_reuse", - "problems/payload_too_large", - "problems/unsupported_media_type", - "problems/unauthenticated", - "problems/invalid_credential", - "problems/forbidden", - "problems/entitlement_required", - "problems/not_found", - "problems/conflict", - "problems/gone", - "problems/invalid_state", - "problems/quota_exceeded", - "problems/rate_limited", - "problems/concurrency_limit_reached", - "problems/safety_intervention", - "problems/content_policy", - "problems/jurisdiction_restricted", - "problems/internal", - "problems/upstream_failure", - "problems/upstream_timeout", - "problems/service_unavailable", - "problems/no_capacity" - ] - } - ] - }, - { - "group": "Help", - "root": "getting-started/troubleshooting", - "icon": "life-buoy", - "pages": [ - "status", - "security/overview" - ] - }, - { - "group": "Changelog", - "root": "changelog", - "icon": "history", - "pages": [ - "platform" - ] - } - ] - }, - "contextual": { - "options": [ - "copy", - "view" - ] - }, - "icons": { - "library": "lucide" - } + ] } diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..22c039c --- /dev/null +++ b/favicon.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none" role="img" aria-label="Cortex Docs"> + <rect width="32" height="32" rx="7" fill="#1F4945"/> + <path d="M10 8h9a3 3 0 0 1 3 3v13H13a3 3 0 0 1-3-3V8z" fill="#FAF8F4" opacity="0.95"/> + <path d="M13 8v16" stroke="#1F4945" stroke-width="1.2" opacity="0.5"/> + <path d="M19 14c4-6 7-4 6 1-4 1-5 5-4 8-3-2-4-5-2-9z" fill="#1F4945"/> +</svg> diff --git a/getting-started/accounts.mdx b/getting-started/accounts.mdx index 76b8b01..bbb42a4 100644 --- a/getting-started/accounts.mdx +++ b/getting-started/accounts.mdx @@ -1,14 +1,12 @@ --- title: "Accounts and sign-in" -description: "Chat works as a guest. Sign in once for projects, files, Code, Bot, and the CLI — the same account everywhere." -keywords: ["guest", "sign in", "membership", "plan"] +description: "Cortex Chat works without an account. One sign-in opens Chat, Code, Bot, Security, the desktop apps and the CLI." +icon: "user" --- -You sign in from the product: choose **Sign in to save your work** in the sidebar footer, or the **Sign in** button on any public page at [cortex.foundation](https://cortex.foundation). This site describes what the account unlocks; it does not document the sign-in protocol. +Cortex is one account on `cortex.foundation`. The same sign-in opens Cortex Chat, Cortex Code, Cortex Bot, Cortex Security, the desktop apps and Cortex CLI. Chat is the only surface that works before you sign in: you can open it, ask a question and read the answer without an account at all. -<Frame caption="The sign-in dialog. Chats, projects, and Bot routines follow a signed-in account across devices."> - <img src="/images/product/accounts-sign-in.png" alt="Sign in to keep your sessions — continue with Google, Apple, email, or single sign-on" /> -</Frame> +This page covers the difference between a guest and a signed-in member, the sign-in methods as they appear on screen, what changes the moment you sign in, how sessions behave across devices, and the two gates that stand in front of Code and Bot during the beta. ## Guest and member @@ -20,50 +18,98 @@ A **guest** is anyone using Chat before signing in. A **member** is a signed-in | Projects, Library, memory, plans | No | Yes | | Connected apps and MCP servers | No | Yes | | GitHub connection | No | Yes | -| Code and Bot working UI | No — the public product page and the **This space is reserved** gate | Yes | -| Design canvases | No | Yes | -| CLI and desktop apps | No | Yes | -| Data export and account deletion | No | Yes, after two-factor confirmation | +| Cortex Code and Cortex Bot | No, the reserved-space gate appears instead | Yes | +| Cortex Design canvases | No | Yes | +| Desktop apps and the CLI | No | Yes | +| Custom instructions | No | Yes | +| Report a bug | No | Yes | +| Two-factor authentication | No | Yes | +| Data export and account deletion | No | Yes, after a two-factor confirmation | -The rule behind the table: a guest cannot create anything it could not come back to revoke. That is why a guest cannot connect an app, hold a GitHub grant, or own a bot. +One rule explains every row: a guest cannot create anything it could not come back to revoke. A guest session cannot be signed back into later to withdraw a grant, so Cortex never lets it make one. Where a guest meets a wall, the product says the capability needs an account and offers to sign in rather than hiding the control. ### The guest allowance -The banner above the composer shows the live number — at the time of writing, **100 messages today** and **500 this month**, with reset timers under **Settings → Plan & billing**. Guest chats live in the browser session; sign in before you close the tab if you want to keep them. +A banner above the composer counts what is left, in the form `{left} of {limit} free messages left`. The guest ceiling is **100 messages today** and **500 messages this month**. When a window is used up, the banner becomes `Sign in to continue`. + +Guest conversations live in the browser session. Sign in before you close the tab if you want to keep them. The guest allowance belongs to that browser session and ends at sign-in: it does not carry over, and the Free plan's own windows start fresh on the account. ## Ways to sign in -The dialog offers **Continue with Google**, **Continue with Apple**, an email address, and **Single sign-on (SSO)** for organisations. Whatever you choose, it is one account: the web app, the desktop app, the Bot desktop app, and the CLI all recognise it. +Sign-in happens in a dialog on `cortex.foundation`, and the dialog says so: `Sign-in happens here, on cortex.foundation — never on another domain.` It is titled **Sign in**, and it explains what an account buys you with `Your chats, projects and Bot routines follow you across devices. Nothing is lost when you close the tab.` + +<Steps> + <Step title="Open the dialog"> + Choose **Sign in to save your work** in the sidebar footer, or **Sign in** on any public page. + </Step> + <Step title="Pick a method"> + **Continue with Google**, **Continue with Apple**, **Continue with email**, or **Single sign-on (SSO)** for organisations. + </Step> + <Step title="For email, enter the code"> + Type your address in `Your email address`. Cortex emails a code and the dialog says `We emailed a code to {email}. It expires quickly.` Enter it under **Code**. `Retry` only ever re-sends on a click, never on a timer, because retrying sends another email. + </Step> + <Step title="For SSO, enter your work email"> + Under **Sign in with SSO**, enter your work email and choose `Continue`. You are handed to your organisation's identity provider and returned to Cortex. + </Step> + <Step title="Let it close itself"> + The dialog shows `You're signed in.` and `Opening your workspace… This chat is kept.`, then closes on its own after about a second. Press Enter or Esc to close it now. + </Step> +</Steps> + +While a sign-in hop is in flight, only the close control works, and closing it cancels the hop. The dialog also links the two documents you agree to: `Privacy policy` and `Terms of service`. + +<Note> +The sign-in dialog has no second-factor field. If your organisation requires a second factor, it runs during the identity step rather than in this dialog. In Cortex itself, two-factor is a confirmation for export and deletion. See [Two-factor authentication](/getting-started/two-factor). +</Note> + +The CLI signs in from the terminal with `cortex login`, which opens the same browser dialog. See [CLI sign-in](/cli/sign-in). + +## What signing in changes on screen -The CLI signs in from the terminal with `cortex login`, which opens the browser flow; machines without a browser use a device code. See [CLI sign-in](/cli/sign-in). +Signing in does not navigate. The transcript you were reading stays exactly where it was. The shell picks up the new account, the sidebar footer switches from `Guest` and `Sign in to save your work` to your account row, and the notification and quota panels restart their reads for the new identity. Signing in as a different account resets those panels to their loading state rather than briefly showing the previous account's rows. -## After you sign in +Your account details then live in **Settings → General**: **Email** (`The address you sign in with.`, read-only) and **Display name** (`How Cortex refers to you.`, up to 120 characters, saved with `Saving…` then `Saved`). A guest sees `You're browsing as a guest.` and `Sign in to manage your account` in place of those two rows. -- **Chat** keeps your conversations, projects, Library, memory, and plans across devices. -- **Code** opens the working UI at `/code` instead of the guest gate. Connect GitHub from Code Home or **Settings → Integrations**. -- **Bot** opens the setup form on first visit, then your list of bots in the sidebar. -- **Settings → Account** switches from “You're browsing as a guest” to your account controls. +## Sessions and devices -## Your data +A signed-in account follows you across devices: the same chats, projects and Bot routines are there when you open Cortex somewhere else. Nothing has to be transferred by hand. -**Settings → Data & privacy** holds export and deletion. Signed-in members confirm with an authenticator app first. Deletion takes effect within 30 days. What Cortex stores: your account details, conversations and attachments while history is on, saved memories, and billing records. The content of connected apps is read at question time and discarded — it is never stored. See [Security](/security/overview). +When a session ends on its own, Cortex says `Please sign in again` with `Your session has expired. Signing in again picks up where you left off.` Signing in returns you to what you were doing. + +Settings has no device list and no remote sign-out today. Ending every session at once is drawn as **Lockdown mode** under **Settings → Data & privacy → Account security**, but the row reads `Lockdown is not available on this account yet.` **Login alerts**, on the same row group, are drawn on and disabled with `Login alerts are not available on this account yet.` <Note> -Cortex Chat is per account, not a shared workspace. There is no teammate invite on a thread. See [Sharing and teams](/chat/sharing). +Cortex is per account. There are no teams, no shared workspaces and no invitations to send. The role and directory rows you can see under **Settings → Integrations** describe an organisation you cannot create here. See [Sharing](/chat/sharing). </Note> -## Troubleshooting +## The beta gates for Code and Bot + +Cortex Code and Cortex Bot are member surfaces, and during the beta they are also invitation-only. You meet one of two dialogs, in this order. -| What you see | What it means | -| --- | --- | -| **This space is reserved** on `/code` or `/bot` | You are a guest. Sign in, or **Continue in Chat**. | -| **Sign in to continue** in the composer banner | The guest allowance for today or this month is used up. Sign in to continue on the Free plan. | -| Two-factor prompt on export or deletion | Expected. A signed-in account confirms destructive actions with an authenticator app. | -| The CLI asks you to sign in again | The stored session expired or was cleared. Run `cortex login`. | +| You are | What appears | Buttons | +| --- | --- | --- | +| Not signed in, opening Code or Bot | `This space is reserved` with `{product} is a reserved space for signed-in accounts. Chat stays available without an account.` | `Continue in Chat` and `Sign in` | +| Signed in but not invited | `{product} is in closed beta` with `{product} is available to invited accounts. Chat stays open for everyone.` | `Continue in Chat` only | -## Next +Neither dialog can be dismissed: there is no close button, Escape does nothing and clicking outside does nothing. Neither is a redirect either. The address bar keeps the URL and the public product page stays visible behind the dialog. Cortex Chat is never gated. -- [Plans and quotas](/getting-started/plans) — what each plan includes and how limits behave. -- [Settings](/getting-started/settings) — theme, language, models, privacy, billing. -- [Sharing and teams](/chat/sharing) — what is per account, and where team features live. -- [CLI sign-in](/cli/sign-in) — the terminal side of the same account. +## When sign-in does not work + +| What you see | What it means | What to do | +| --- | --- | --- | +| `The sign-in window could not be opened. Allow pop-ups and try again.` | The browser blocked the sign-in window | Allow pop-ups for `cortex.foundation`, then retry | +| `That sign-in was not completed. Choose another option.` | The hop was cancelled before it finished | Start again, or pick another method | +| `This address does not look valid. Check the domain after the @.` | The email address was rejected before anything was sent | Correct the address | +| `{email} does not have access to this Cortex space (403).` | The account is not in this space | `Ask your administrator for an invitation, or try another account.` | +| `This sign-in attempt has expired. Start again.` | The emailed code or the attempt aged out | Request a new code | +| `The server could not be reached. Try again.` | Cortex could not be reached | Choose `Retry`, and check [status.cortex.foundation](https://status.cortex.foundation) if it persists | +| `Sign in to continue` in the composer banner | The guest allowance for today or this month is used up | Sign in to continue on the Free plan, or wait for the reset | + +## Related + +- [Two-factor authentication](/getting-started/two-factor) - the confirmation that protects export and deletion. +- [Plans and quotas](/getting-started/plans) - the guest allowance, and what each plan lifts. +- [Settings](/getting-started/settings) - every tab, and where your account controls live. +- [Data and privacy](/getting-started/data-and-privacy) - export, deletion, cookies and memory. +- [CLI sign-in](/cli/sign-in) - the terminal side of the same account. +- [Troubleshooting](/getting-started/troubleshooting) - cross-product symptoms and what they mean. diff --git a/getting-started/choose-a-product.mdx b/getting-started/choose-a-product.mdx new file mode 100644 index 0000000..c599af9 --- /dev/null +++ b/getting-started/choose-a-product.mdx @@ -0,0 +1,88 @@ +--- +title: "Which product do I need?" +description: "A task table that maps what you want to do to the right Cortex application, plus what each one needs before it will open." +icon: "signs-post" +--- + +Cortex has six applications and they overlap less than their names suggest. **Cortex Chat** is a conversation, **Cortex Code** is work inside a repository, **Cortex Bot** is an agent with a computer of its own, **Cortex CLI** is Code in a terminal, **Cortex Design** is a board, and **Cortex Security** is review on a pull request. Picking the wrong one usually feels like a missing feature rather than a wrong turn, which is why this page exists. + +Start from the task, not from the product. The first table maps what you want to do to the application that does it. The second says what each one needs before it will open, because some are member-only and two are still in closed beta. The last section covers the pairs that genuinely overlap. + +## Start from the task + +| You want to | Open | What it needs | +| --- | --- | --- | +| Ask a question, write something, work through an idea | **Cortex Chat** | Nothing. A browser is enough | +| Summarize a document, or ask about a picture | **Cortex Chat** | An account, because attachments do | +| Generate a picture | **Cortex Chat** | An account for anything beyond the guest allowance | +| Keep standing instructions and files for a recurring topic | **Cortex Chat** projects | An account | +| Have Cortex do something on a schedule and tell you the result | **Cortex Chat** scheduled tasks | An account | +| Change files in a repository, run its tests, open a pull request | **Cortex Code** | An account and a closed-beta invitation | +| Do that on your own machine, or on a server you own | **Cortex Code** on desktop, or the **CLI** | The desktop app or the CLI | +| Script the same work, or run it in a pipeline | **Cortex CLI** | An account and a terminal | +| Hand over ongoing work that needs a browser, clicks and patience | **Cortex Bot** | An account and a closed-beta invitation | +| Get a pull request reviewed where it already lives | **Cortex Security** | An account and a repository | +| Lay out frames, components and notes on a board | **Cortex Design** | An account and the Cortex Design desktop app | + +## What each one needs + +| Application | Account | Closed beta | Where the work happens | Install | +| --- | --- | --- | --- | --- | +| **Cortex Chat** | No, within the guest allowance | No | The browser, or the desktop app | None | +| **Cortex Code** | Yes | Yes, invited accounts only | An isolated cloud runtime, or a host you own from desktop or the CLI | Only for a host you own | +| **Cortex Bot** | Yes | Yes, invited accounts only | A cloud computer with a desktop you can watch | None | +| **Cortex CLI** | Yes | Runs Code sessions | Your terminal, on your own checkout or a remote host | Yes | +| **Cortex Design** | Yes | No | The Cortex Design desktop app, on a canvas hosted from Chat or Code | Yes | +| **Cortex Security** | Yes | No | Your repository, on the pull request itself | A repository installation | + +<Note> +The two gates read differently. As a guest, opening Code or Bot shows **This space is reserved**, with **Sign in** or **Continue in Chat**. Signed in but not yet invited, you get a closed-beta dialog with **Continue in Chat** only. Neither can be dismissed and neither redirects. Chat is never gated. +</Note> + +## When two of them could work + +**Chat or Code?** If the answer is text, stay in Chat. If the answer is a commit, use Code. Chat can reason about a snippet you paste, but it has no workspace, no branch and no diff. A Code session is a timeline of work with approvals and a change set, not a transcript with a different icon. + +**Code in the browser, on the desktop, or the CLI?** All three run the same kind of session. The browser gives you an isolated cloud runtime with nothing to install. The desktop app and the CLI add a host you actually own, which is the only way to work against a checkout, a device or a server that Cortex cannot reach on its own. The CLI is also the one you can put in a script or a pipeline. + +**Code or Bot?** Code is scoped to a repository and produces changes you review. A Bot has a general-purpose computer: it browses, clicks and works through a task on a desktop you can watch, and it parks the consequential steps for your approval. If the job is mostly web work, filling things in, or something that runs again tomorrow, that is a Bot. + +**Code or Security?** Cortex Code is where you make a change. Cortex Security is where a change gets read: it reviews the pull request in place, with no diff to paste, and writes its verdict as a check run and a summary. Cortex never approves a pull request on your behalf. + +**Design or a Chat canvas?** A Design canvas is a board with components, versions and a reusable library, opened in its own desktop app. It is hosted from Chat or Code but it is not a markdown sidecar inside a conversation. + +## Still not sure + +Start in Chat. It is the only application you can open without an account, it is the one that is never gated, and it is the fastest way to find out whether your task actually needs a repository, a computer or a board. Signing in later does not lose the conversation on screen. + +<CardGroup cols={3}> + <Card title="Cortex Chat" icon="comments" href="/chat/index"> + Conversation, research, documents, pictures, projects and scheduled work. + </Card> + <Card title="Cortex Code" icon="code" href="/code/index"> + Sessions in a repository, with runtimes, approvals and a change set. + </Card> + <Card title="Cortex Bot" icon="robot" href="/bot/index"> + An agent with its own computer, its own routines and its own inbox. + </Card> + <Card title="Cortex CLI" icon="terminal" href="/cli/index"> + The same Code sessions from a terminal, a script or a pipeline. + </Card> + <Card title="Cortex Design" icon="pen-ruler" href="/design/index"> + Canvases, versions, a component library and export. + </Card> + <Card title="Cortex Security" icon="shield-halved" href="/security/index"> + Pull-request review in place, with check runs and findings. + </Card> +</CardGroup> + +Your plan changes how much of any of these you get rather than which ones you can open: message windows, how many projects you can keep, and how much room the Library gives you. See [Plans and quotas](/getting-started/plans). **Cortex Bounty** is a programme rather than an application you open, and has [its own section](/bounty/index). + +## Related + +- [What is Cortex](/getting-started/what-is-cortex) +- [Quickstart](/getting-started/quickstart) +- [Accounts and sign-in](/getting-started/accounts) +- [Plans and quotas](/getting-started/plans) +- [Ways to run Cortex](/getting-started/downloads) +- [Troubleshooting](/getting-started/troubleshooting) diff --git a/getting-started/data-and-privacy.mdx b/getting-started/data-and-privacy.mdx new file mode 100644 index 0000000..84410a2 --- /dev/null +++ b/getting-started/data-and-privacy.mdx @@ -0,0 +1,141 @@ +--- +title: "Data and privacy" +description: "Export or delete your Cortex data, set a cookie preference, manage memory, and see what Cortex keeps and for how long" +icon: "user-shield" +--- + +Everything Cortex holds about your account is managed from one place: **Settings → Data & privacy**. It is the tab where you export a copy of your data, schedule a permanent deletion, decide whether optional analytics may run, review what Cortex has remembered about you, and read what this deployment does and does not certify. Settings opens as an overlay over Chat, Code or Bot, so you never lose your place. + +This page walks through each section of that tab in the order you meet it, says which controls need a signed-in account, and ends with how long Cortex keeps things. Some rows are drawn but not finished; where that is the case, it is called out rather than described as working. + +<Note> +Most of this tab needs an account. A guest can open it and read it, but export, deletion, memory, activity and two-factor all say so and offer to sign in rather than disappearing. +</Note> + +## Export your data + +**Export my data** builds a JSON file, `cortex-data-export.json`, while you wait. There is no queue and no status page. + +<Steps> +<Step title="Open the tab"> +Choose **Settings** in the sidebar footer, then **Data & privacy**. Scroll to **Your data** (`Export everything we hold, or delete it permanently. Deletion takes effect within 30 days.`). +</Step> +<Step title="Start the export"> +Choose **Export my data**. The button becomes `Preparing export…`. +</Step> +<Step title="Confirm with your authenticator"> +Export is a sensitive action. If you are asked, choose **Confirm to continue** and type the code from your authenticator app. Without an enrolled authenticator and a recent confirmation, the export refuses with `Confirm two-factor authentication, then try again.` +</Step> +<Step title="Take the file"> +The download starts and the row confirms `Download started — a JSON copy of what we hold for this account.` +</Step> +</Steps> + +The bundle contains what your account can actually see: your account details, conversation **metadata**, your memories, and Library file metadata such as id, filename, kind, size, source and created date. It does **not** contain message bodies and it does not contain file bytes. A member's export also carries Code session metadata, the names of bots they own, Design canvas metadata, project metadata and Cortex Data records, never the token. A guest's export has none of those keys, because a guest cannot own them. + +Two values live in your browser rather than on the server, your trusted contact and your date of birth. They are included in the file so the export is complete, and the tab says so: `Trusted contact and date of birth are stored in this browser, not on our servers. They are included here so this export is complete, and they are removed when you erase your account.` + +## Delete your account and data + +**Delete all data** schedules a real erasure, not a flag on a record. + +<Steps> +<Step title="Choose Delete all data"> +From **Your data**, choose **Delete all data**. The confirm dialog reads `Delete all your data?` and `This schedules your account, conversations, memories and files for permanent deletion.` +</Step> +<Step title="Read the grace period"> +`Erasure runs after a 30-day grace period. Signing in again before it runs cancels the request; after it runs, nothing can be restored.` The dialog cannot be dismissed by clicking outside it. +</Step> +<Step title="Confirm"> +Enter your authenticator code if you are asked, then choose **Delete all data**. The row becomes `Deletion requested — your data will be permanently erased within 30 days. Signing in again during that time cancels it.` +</Step> +</Steps> + +The request covers your account, conversations, memories, files, bots and canvases. Asking a second time while a request is open changes nothing. To cancel, sign in again before the 30 days are up. Once erasure has run, nothing can be restored and signing in is refused. + +## Cookies and Global Privacy Control + +On your first visit, the banner **Cookies on this site** offers **Necessary only** and **Allow optional**. The same choice lives under **Cookies** in this tab, as two rows: + +| Row | What it covers | +| --- | --- | +| **Necessary** | `Session, language, and this preference. Always on — Cortex cannot work without them.` The toggle is on and cannot be changed. | +| **Optional analytics** | `Helps us understand how the product is used. Off until you allow it. Nothing in this build loads an optional tracker; the preference is recorded so a future one cannot fire without it.` | + +The default is deny, and the product fails closed while it is still reading your preference. If saving the choice to your account fails, it still holds in this browser and the banner says so: `Your choice is saved in this browser. We could not update the account record — try again from Settings.` + +If your browser sends a **Global Privacy Control** signal, Cortex honours it instead of asking again: `Your browser sent a Global Privacy Control signal. Optional cookies stay off. We do not sell personal information.` The optional row is disabled while the signal is present, and a signal always wins over an "allow" sent from the page. To withdraw the opt-out, turn the signal off in your browser, then allow optional analytics explicitly. + +## Memory + +**Memory** is where Cortex keeps standing preferences and facts you have shared so answers get more personal over time. Three controls sit above the list: + +- **Use memory**: `When off, Cortex neither recalls nor writes new memories. Existing ones stay until you delete them.` +- **Include sensitive topics**: `When off, Cortex skips health, finances, and similar topics when saving memories.` +- **How long to keep memories**: `Keep until deleted` or a number of days. `Applies to new and existing memories on this account. Project memories follow the same window.` + +Below them, **Account memory** and **Project memory** list what has been saved, tagged **Facts**, **Context**, **Preferences**, **Instructions** or **Other**. You can **Search memories**, **Edit** or **Delete** a single entry, **Erase account memories**, **Erase project memories**, **Export memories**, or **Import memories** (`Paste exported lines. Import only adds; it never overwrites or deletes.`). + +Temporary chats never read or write memory. If memory cannot be read at all, it stays off rather than guessing: `Memory could not be loaded, so it stays off. Nothing is listed or saved until the setting can be read.` + +## Chat history and improving the model + +Two rows near the top of the tab are drawn but disabled, both badged `COMING SOON`: + +- **Save chat history**: the toggle is on and cannot be changed. Its copy reads `Conversations are kept in your account so you can pick them up on any device. If you turn this off, new chats disappear when you close them.` +- **Improve the model**: the toggle is off and cannot be changed. Its copy reads `When on, a sample of your conversations may be reviewed to train future models. Off by default — your chats are never used without this setting.` + +Neither is a live setting yet, so there is nothing here to turn on or off today. Treat the copy as a description of the control that is coming, not as a preference recorded against your account. + +## Activity, computer history and account security + +**Activity** (`Review account activity across Chat, Code, and Bot.`) lists the `Last {days} days` with columns **When**, **Actor** and **Action**. Actors are `you`, `admin`, `bot` or `code`; actions include `Signed in`, `API key minted`, `Connector connected`, `Consent updated`, `Export started`, `Deletion queued`, `Bot approval granted` and `PR opened`. When it cannot be read it says so rather than showing an empty table, including `Activity is not available on this deployment yet. The events are recorded, but this list cannot read them back yet.` + +**Computer history** belongs to the desktop app: `On the desktop app, record which apps and sites this computer opened — times only, no screenshots or audio. Off by default. Private browsing is never logged.` In a browser the row reads `Recording runs in the Cortex desktop app, not in this browser.` + +**Account security** holds **Login alerts** and **Lockdown mode**. Neither is available on this account yet: the alerts toggle is fixed with `Login alerts are not available on this account yet.`, and the lockdown button answers `Lockdown is not available on this account yet.` + +**Two-factor authentication** also lives in this tab, because export and deletion depend on it. See [Two-factor authentication](/getting-started/two-factor) for enrolment and recovery. + +**API keys** are reserved rather than issued. The section explains itself: `Create, rotate and revoke stay disabled until the account API stores only hashes and can deny expired keys immediately.` There are no programmatic keys today. + +## Compliance + +**Compliance** is a section inside this tab, not a separate Settings tab. Its lede is `What this deployment certifies — and what it does not.` + +**Data region** is pinned to the region this deployment runs in, shown as a `PINNED · {region}` pill with the zones `EU` / `Frankfurt · eu-central-1` and `US` / `Virginia · us-east-1` marked `SELECTED`, `AVAILABLE` or `NOT OFFERED`. You cannot move a region from the app: `Region changes are not available in the app: they require a new deployment and a scheduled migration window.` + +**Attestations** are listed as statuses, never as seals: `Listed exactly as they stand. A status is not a certificate.` **SOC 2 Type II** reads `No report on file. We will say so when one exists.`, **GDPR readiness** reads `Readiness work is tracked; no certification is claimed.`, and **HIPAA** reads `Not certified. PHI needs a signed BAA first.` The section closes with the rule the product holds itself to: `Product copy never claims certification until an attestation exists.` + +A **BAA · PHI-safe defaults** card explains that covered entities need a signed BAA before any PHI is processed, and that the defaults it lists are already on, so nothing about them changes when one is signed. **Request a BAA** opens an email; sending it signs nothing. The HIPAA certification claim row reads `NEVER · UNTIL ATTESTED`. + +<Warning> +Cortex is not certified under SOC 2, GDPR or HIPAA, and this tab never says it is. Read the statuses literally. +</Warning> + +## What Cortex stores, and for how long + +The tab closes with a card headed `WHAT WE STORE`: `Your account details, conversations and attachments while history is on, saved memories, and billing records. We never store the content of connected apps — Cortex reads them at question time, then discards the data.` + +Conversations, Chat library files and Design canvases you still hold are not deleted on a schedule; they stay until you delete them or delete the account. Backups are kept 35 days. Operational records are pruned on their own schedule: + +| Record | Kept for | +| --- | --- | +| Audit log | 90 days queryable, then archived | +| Routing decisions | 30 days | +| Usage events | 1 year | +| Sandbox executions | 30 days | +| Delivered events | 7 days | +| Idempotency records | 24 hours | +| Revoked sessions | 30 days | +| Safety events | 2 years | +| Data-request records | 3 years | +| Erasure log | Kept indefinitely, identifiers only, never content | + +## Related + +- [Two-factor authentication](/getting-started/two-factor) +- [Settings](/getting-started/settings) +- [Memory](/chat/memory) +- [Security and privacy](/reference/security-and-privacy) +- [Accounts and sign-in](/getting-started/accounts) diff --git a/getting-started/desktop.mdx b/getting-started/desktop.mdx index 0a358c6..9b561ea 100644 --- a/getting-started/desktop.mdx +++ b/getting-started/desktop.mdx @@ -1,69 +1,152 @@ --- -title: "Desktop app (Chat + Code)" -description: "The Cortex desktop app carries Chat and Code, and adds This PC and SSH hosts for Code sessions. The browser stays Cloud-only." -keywords: ["app", "This PC", "SSH", "local"] +title: "Cortex desktop app" +description: "Install and sign in to the Chat and Code desktop app, run Code on This PC, and let it keep itself up to date." +icon: "desktop" --- -The Cortex desktop app is the same Chat and Code you know from the browser, with one addition that only a native app can offer: Code sessions can run on **This PC** or over **SSH** as well as in the Cloud. Download it from [releases.cortex.foundation](https://releases.cortex.foundation) and sign in when the app asks — same account as the web. - -## Install and sign in +The Cortex desktop app carries **Cortex Chat** and **Cortex Code** in a single window. It draws its +own title bar with a switcher between **Chat** and **Code** and its own window controls, and it is +the only client that can run a Code session on your own machine. + +This page covers what the installer does on each platform, the first launch and signing in, what +the app adds over a browser tab, how to start a Code session on **This PC**, notifications, and how +the app updates itself. + +<Note> +Cortex does not publish a public download page yet, so there is no installer link here. See +[Ways to run Cortex](/getting-started/downloads) for the full picture. +</Note> + +## Install + +<Tabs> + <Tab title="macOS"> + Open the downloaded disk image and drag **Cortex** to your Applications folder, then open it. + The build is notarised, so you do not have to override any security warning. + </Tab> + <Tab title="Windows"> + The installer shows its steps rather than installing in one click, and it lets you change the + installation directory. It installs for your user only, so administrator rights are not + required. It creates a desktop shortcut and a Start-menu shortcut, both named **Cortex**. A + portable build for 64-bit Windows is also published for people who would rather not run an + installer. + </Tab> + <Tab title="Linux"> + Either download the portable application image and make it executable, or install the Debian + package with your package manager. The launcher entry is named **Cortex** and described as + `Cortex Chat + Code`. Installing also lets a completed sign-in hand you back to the app. + </Tab> +</Tabs> + +## First launch <Steps> - <Step title="Download"> - Open [releases.cortex.foundation](https://releases.cortex.foundation) and pick the build for your platform. + <Step title="Read the welcome screen"> + The first launch shows a welcome screen, once. It names your platform (**Cortex for Mac**, + **Cortex for Windows** or **Cortex for Linux**) above the line **Chat and Code — on this + machine.** and the body `Sign in for Cortex models and cloud runtimes, or continue on This PC + with your own provider keys.` + </Step> + <Step title="Choose Get started or Continue without an account"> + **Get started** takes you to the sign-in screen. **Continue without an account** skips sign-in + and lets you work on This PC with your own provider keys. </Step> - <Step title="Open and sign in"> - Launch the app. It asks you to sign in with your Cortex account; guests cannot use Code, so the desktop app expects a member. + <Step title="Sign in"> + On the **Sign in** screen, under **Continue to Cortex**, pick **Continue with Google**, + **Continue with GitHub**, **Continue with Apple** or **Continue with SSO**, or type an **Email + address** and **Password**. The email and password form stays inside the app window. </Step> - <Step title="Choose a host for Code"> - Start a Code session and pick **Cloud**, **This PC**, or **SSH**. Chat needs no host — it works exactly as it does in the browser. + <Step title="Finish in your browser, if you chose a button"> + Each of the four buttons opens your system browser. When you are done there, a Cortex page says + **Finish signing in in the Cortex app** and hands you back. If the app does not come forward by + itself, select **Open Cortex**, then close the browser window. </Step> </Steps> -## What desktop adds +To work without a Cortex account, open **Settings → Providers** and either point the app at a model +server running on this machine or paste a provider key. On the desktop app that key is kept in your +operating system's own credential store, not in the app. -| Surface | In the browser | On desktop | -| --- | --- | --- | -| Chat | Yes | Yes — same account, same projects | -| Code Cloud | Yes | Yes | -| Code on **This PC** | No | Yes | -| Code over **SSH** | No | Yes — shell only, no desktop | -| Bot Cloud | Yes | Use the web app or the [Bot desktop app](/bot/desktop) | -| Design working UI | No | Separate [Design desktop app](/design/desktop) | +## What the desktop app adds over the browser -Web Code stays Cloud-only. That is host placement — the code runs where the host is — not a missing catalog entry. +| On the desktop app | In a browser tab instead | +| --- | --- | +| **This PC** as a Code runtime: agents act on a folder you pick on this machine | Cloud, a paired machine, or SSH, never the local machine | +| A local terminal and local Git for Code runs | Nothing local runs in a tab | +| Your provider keys kept in the operating system's own credential store | Keys never reach the tab, and the service answers with a mask | +| Its own window chrome, with the product switcher and window controls | Normal browser chrome | +| Notifications raised by your operating system | Browser notifications, once you allow them | +| Opening a local folder through the system's folder picker | No local folder access | +| Conversations and sessions kept on this machine | Everything comes from the service | +| Automatic updates | The tab is always current | +| A double-tap capture chord: **⌘ ⌘** on Mac, **Alt Alt** on Windows | `This chord lives on the desktop app. The web has no global hotkey.` | +| Recording which apps and sites this computer opened, times only, off by default | `The web app does not store desktop history.` | + +The theme, the notification inbox, an optional remote-host address and whether you have seen the +welcome screen are preferences of this device, not account settings, so they do not follow you to +another machine. + +## Run a Code session on This PC -## Hosts for Code +<Steps> + <Step title="Switch to Code and start a session"> + Use the switcher in the title bar, then start a new session and choose **This PC**. + </Step> + <Step title="Pick a folder"> + The system's folder picker opens. There is no workspace-name field: the folder's name identifies + the repository. If you cancel the picker, no session is created. + </Step> + <Step title="Work"> + Once the session has some history, the composer shows chips for the runtime, **This PC**, the + repository, the branch and the worktree. Each action asks for **Allow**, **Always** or + **Deny**, and the session runs in **Ask**, **Plan** or **Agent** mode, with **Agent** as the + default. + </Step> +</Steps> -| Host | Where the workspace tools run | Good for | -| --- | --- | --- | -| **Cloud** | An isolated Cloud guest prepared for your repository | Anything you would do in the browser | -| **This PC** | Your machine, in the project directory you choose | Local toolchains, private networks, hardware | -| **SSH** | A host you register, over its shell | Servers and build boxes you already have | +If nothing on this machine is attached yet, the session says so: `This session runs on This PC, and +no host is connected. Pair one from the Host pane and the composer comes back.` Cortex never +silently moves a This PC session into the cloud. If the place you chose is unavailable, the session +tells you instead of relocating. -This PC and SSH need an already connected Code session; Cortex never silently substitutes the Cloud for a host you selected. The CLI exposes the same hosts through `CORTEX_COMPUTER` — see [Code on desktop](/code/desktop) and [CLI configuration](/cli/configuration). +To use a machine you reach over the network, go to **Code → Connect a server** and follow the +connection form. To attach to a machine that is already running Cortex Code, open **Code → +Settings** and enter that host's address; only the address is needed. The host status is shown as +one of **Cloud only**, **Connecting**, **Connected**, **Disconnected**, **Cloud session running**, +**Permission blocked** or **Failed wake**. -## Two desktop apps +To let Code see your repositories, open **Code → Settings → Integrations** and select **Connect +GitHub**. The installation page opens in your system browser. There is no personal-access-token +field to fill in. -The Cortex desktop app has a **Chat and Code** sidebar. Bots live in their own desktop app with an **agents, routines, and channels** sidebar and no Chat or Code — see [Bot desktop](/bot/desktop). Design's working UI is a third app — see [Design desktop](/design/desktop). +## Notifications -## Which app do I want? +Chat and Code share one notification inbox, and the desktop app also raises your operating system's +own notifications when the window is not focused. You are notified when a scheduled task produces +something, when you are mentioned, when a Code run finishes, when a Code run is waiting on a +permission, when a bot needs an answer, and when a computer fails to wake. -| You want | Install | -| --- | --- | -| Chat, and Code on This PC or SSH | **This app** — [Downloads](/getting-started/downloads) | -| Bots on This PC, plus agents, routines, and channels in one window | [Bot desktop](/bot/desktop) | -| Edit Design canvases | [Design desktop](/design/desktop) | -| Code from a terminal, a script, or CI | [CLI](/cli/install) | +Open the in-app centre from the command palette (**Notifications**), where the empty state reads +**Nothing new.** The **Notifications** page under Code shows the same items, with the empty state +**Nothing needs you** and `Runs that finish or fail while you are elsewhere will land here.` +Mark-as-read is offered only while something is unread. -The browser covers Chat and Code in the Cloud. Install an app when you need a host, an editor, or a terminal the browser cannot provide. +## Updates -## Updating +The app checks for an update when it starts and then every four hours, and downloads it quietly in +the background. While it downloads you may see `Downloading Cortex…` with a percentage. When a build +is ready a toast says `Cortex {version} is ready to install.` with **Restart now** and **Later**. +Choosing **Later** installs the update the next time you quit. -Desktop builds update from the feed on [releases.cortex.foundation](https://releases.cortex.foundation); the web app is always current. See [Downloads](/getting-started/downloads). +The app never moves you to an older version, and it keeps checking the channel the build you +installed came from, so there is no channel picker inside the app. Mac builds are notarised and +Windows builds are code-signed, and Windows verifies the signature of an update before installing +it. In a browser tab the update banner never appears, because there is nothing there to install. -## Next +## Related -- [Code on desktop](/code/desktop) — choosing and using This PC and SSH. -- [Install the CLI](/cli/install) — the same hosts from a terminal. -- [Downloads](/getting-started/downloads) — every way to run Cortex. +- [Ways to run Cortex](/getting-started/downloads) for every application and how each updates. +- [Code on desktop](/code/desktop) for working on This PC in detail. +- [SSH hosts](/code/ssh-hosts) and [Machines](/code/machines) for servers and paired computers. +- [Notifications](/getting-started/notifications) for what Cortex tells you about. +- [Bot desktop app](/bot/desktop) for the separate window that runs your agents. diff --git a/getting-started/downloads.mdx b/getting-started/downloads.mdx index 102da94..29ecf05 100644 --- a/getting-started/downloads.mdx +++ b/getting-started/downloads.mdx @@ -1,78 +1,137 @@ --- -title: "Downloads" -description: "Every way to run Cortex — the web app, the Cortex desktop app for Chat and Code, the Bot desktop app, the Design desktop app, and the CLI." -keywords: ["install", "apps", "desktop", "releases"] +title: "Ways to run Cortex" +description: "Where each Cortex application runs, which ones you can run today, and how each one keeps itself up to date." +icon: "download" +keywords: ["Downloads", "Install", "Apps"] --- -Cortex runs in the browser without installing anything. Download an app when you need a host the browser cannot offer: **This PC** and **SSH** for Code, a desktop home for your bots, or the Design working UI. - -## What to install - -| You want to… | Install | Guide | -| --- | --- | --- | -| Chat, run Code in the Cloud, drive a Bot in the Cloud | Nothing — use [cortex.foundation](https://cortex.foundation) | [Quickstart](/getting-started/quickstart) | -| Run Code sessions on **This PC** or over **SSH** | The **Cortex desktop app** (Chat + Code) | [Desktop app](/getting-started/desktop) | -| Drive Code from a terminal, scripts, or CI | The **Cortex CLI** | [Install the CLI](/cli/install) | -| Run bots from a desktop app built for agents, routines, and channels | The **Cortex Bot desktop app** | [Bot desktop](/bot/desktop) | -| Edit Design canvases | The **Cortex Design desktop app** | [Design desktop](/design/desktop) | - -## Desktop apps - -Desktop builds are published at [releases.cortex.foundation](https://releases.cortex.foundation). Install the build for your platform, open it, and sign in when the app asks — it is the same account as the web app. - -There are two desktop apps because the two jobs are different: - -| App | Sidebar | Adds | -| --- | --- | --- | -| **Cortex desktop** | Chat and Code | This PC and SSH hosts for Code sessions; the same Chat as the web | -| **Cortex Bot desktop** | Agents, routines, channels — no Chat or Code sidebar | A desktop home for your bots | - -Design's working UI is a third, separate desktop app; Chat and Code can still host a canvas that you then open there. - -<p className="ink-cta-row"> - <a className="ink-btn" href="https://releases.cortex.foundation">Open releases.cortex.foundation</a> - <a className="ink-btn ink-btn-quiet" href="/getting-started/desktop">What desktop adds</a> -</p> +Cortex runs in a browser without installing anything. A browser tab cannot touch the files, the +terminal or the windows on your own machine, so Cortex also ships desktop applications and a +command-line tool for the work that has to happen locally. One account covers all of them. + +This page is the map: which application carries which product, where work can run in each one, +which ones are available today, and how each one updates. It deliberately carries no installer +links, because Cortex does not publish a public download page yet. + +## The applications + +| Application | What it carries | Where work can run | Available today | +| --- | --- | --- | --- | +| **Web app** at [cortex.foundation](https://cortex.foundation) | Cortex Chat, Cortex Code and Cortex Bot in a browser tab | Cloud runtimes only | Yes | +| **Cortex desktop app** | Chat and Code in one window, with a switcher between the two | Cloud, a paired machine, a server over SSH, and **This PC** | Yes | +| **Cortex Bot desktop app** | Agents, rooms, routines, plugins and the Inbox. No Chat and no Code. | Cloud, plus **Background computer** on your own machine | Yes | +| **Cortex CLI**, also called the Cortex Code CLI | The same coding agent, in a terminal | Your machine | Yes | +| **Cortex Design desktop app** | Designs, Library, Plugins and Bot jobs | Not applicable yet | No. The web app creates and lists canvases, but the editor is the window | + +<Note> +There is no public download page for the desktop applications yet, and no installer link to give +you. This page describes what each application does and how it behaves once it is installed. +</Note> + +## Pick an application + +<CardGroup cols={2}> + <Card title="Cortex desktop app" icon="desktop" href="/getting-started/desktop"> + Chat and Code in one window, and the only way to run Code on this machine. + </Card> + <Card title="Bot desktop app" icon="robot" href="/bot/desktop"> + A window for your agents: the Inbox, routines, plugins and rooms. + </Card> + <Card title="Cortex CLI" icon="terminal" href="/cli/install"> + The coding agent from a terminal, a script or a continuous-integration job. + </Card> + <Card title="Design desktop app" icon="pen-ruler" href="/design/desktop"> + What the Design window will hold, and what to use in the meantime. + </Card> +</CardGroup> + +## The web app + +Nothing to install and nothing to update. Sign in with your Cortex account and use the product +menu, headed **Switch product**, to move between **Cortex Chat** (`Ask, research and create.`), +**Cortex Code** (`Agents in your repositories.`) and **Cortex Bot** (`A teammate with a +computer.`). The same menu carries a **Desktop app** row and a **Documentation** row, both of which +open in a new tab. + +Two limits are worth knowing before you choose the browser: + +- Cortex Code in a browser runs in the cloud. If something asks for **This PC** or **SSH** from a + tab, the answer is one fixed message: `This PC and SSH are available in the Cortex desktop app, + not in the browser. Use Cloud here.` +- The double-tap capture chord belongs to the desktop app. In the web app the setting says + **This chord lives on the desktop app. The web has no global hotkey.** + +<Warning> +The **Desktop app** row in the product menu is not a download link. It opens the page that hands a +desktop application back to you after you sign in, which says **Finish signing in in the Cortex +app**. +</Warning> + +## The desktop applications + +Two desktop applications ship today, and they do different jobs. + +The **Cortex desktop app** is Chat and Code in one window. It draws its own title bar with the +product switcher and the window controls, keeps your conversations and sessions on this machine, can +open a folder through the system's folder picker, and can run a Code session on **This PC** with a +local terminal and local Git. See [Cortex desktop app](/getting-started/desktop). + +The **Cortex Bot desktop app** is built only around agents. Its rail is **Inbox**, **Routines** and +**Plugins**, with your **Agents** and **Rooms** listed below. It signs you in, runs approvals +through the Inbox, and can be granted **Background computer**, which lets an agent work in windows +that are not frontmost on your own machine. See [Bot desktop app](/bot/desktop). + +A third window, for **Cortex Design**, is not finished: it has no installer and no sign-in, so there +is nothing to install. There is no browser editor to fall back on either: what the web app gives you +today is the **CANVASES** rail, which asks for a design, creates and lists canvases and shows their +status, while the editing itself belongs to the window. See +[Design desktop app](/design/desktop) for what it will hold. ## The CLI -The CLI is one binary, `cortex`, installed from [software.cortex.foundation](https://software.cortex.foundation). The installer verifies a SHA-256 checksum before it writes anything. +The Cortex CLI is a single command-line tool. Its install scripts and its released archives are +published on `software.cortex.foundation`, and the installer checks the published checksum before it +writes anything. On macOS and Linux it installs into `~/.local/bin`, and Python 3.8 or newer must +already be present. On Windows it installs under your local application data folder, in +`Cortex\bin`, and it does not edit your PATH, so add that folder yourself. -<CodeGroup> -```bash macOS and Linux -curl -fsSL https://software.cortex.foundation/install.sh | sh -``` - -```powershell Windows -irm https://software.cortex.foundation/install.ps1 | iex -``` -</CodeGroup> - -Then: +Confirm the install with: ```bash cortex --version -cortex login -cd ~/code/my-project && cortex ``` -<Frame caption="What a fresh install shows, even in a 40-column terminal: Welcome to Cortex, the coding agent CLI, and the empty composer."> - <img src="/images/cli/runtime/40x12/welcome-cortex.png" alt="Cortex CLI welcome splash rendered in a 40 by 12 terminal" /> -</Frame> +Three environment variables change what the installer does: -Full steps, version pins, channels, and updates: [Install the CLI](/cli/install). - -## Updating - -| Surface | How it updates | +| Variable | What it does | | --- | --- | -| Web app | Always current | -| Desktop apps | The updater feed on `releases.cortex.foundation` | -| CLI | `cortex upgrade` (or `cortex upgrade --check` to report only) | +| `CORTEX_VERSION` | Install a specific version | +| `CORTEX_INSTALL_DIR` | Install somewhere else | +| `CORTEX_CHANNEL` | Choose `stable`, `beta` or `nightly` | -## Next +The installer picks the right build for your processor and, on Linux, the right C library variant. +An unrecognised system fails rather than guessing, and the installer refuses to overwrite unrelated +commands. Native Windows ARM64 and 32-bit builds are not published. Full steps are in +[Install the CLI](/cli/install). -- [Desktop app](/getting-started/desktop) — what This PC and SSH add for Code. -- [Bot desktop](/bot/desktop) — the app built around agents, routines, and channels. -- [Design desktop](/design/desktop) — the working UI for canvases. -- [Install the CLI](/cli/install) — checksums, version pins, and channels. +## How each one updates + +| Application | How it updates | +| --- | --- | +| Web app | Always current. Nothing to do. | +| Cortex desktop app | Checks at launch and then every four hours, downloads quietly, then offers **Restart now** or **Later**. Choosing **Later** installs the update the next time you quit. | +| Cortex Bot desktop app | Checks at launch and then every four hours, but downloads nothing until you ask. You press **Check for updates**, **Download update**, then **Restart and install**. | +| Cortex CLI | `cortex upgrade` moves you to the latest build on the stable channel. `cortex upgrade --check` only reports whether an update exists. | +| Cortex Design desktop app | No updater yet. | + +The Cortex desktop app never moves you to an older version, and both desktop applications check +that an update really came from Cortex before installing it. Mac builds are notarised and Windows +builds are code-signed. + +## Related + +- [Cortex desktop app](/getting-started/desktop) for install, sign-in and This PC. +- [Bot desktop app](/bot/desktop) for the agent window and Background computer. +- [Design desktop app](/design/desktop) for the Design window and what to use today. +- [Install the CLI](/cli/install) for the exact install commands and channels. +- [Quickstart](/getting-started/quickstart) if you just want to start in the browser. diff --git a/getting-started/faq.mdx b/getting-started/faq.mdx new file mode 100644 index 0000000..c361653 --- /dev/null +++ b/getting-started/faq.mdx @@ -0,0 +1,187 @@ +--- +title: "Frequently asked questions" +sidebarTitle: "FAQ" +description: "Short answers about accounts, plans, quotas, privacy, languages and what is not built yet, each pointing at the page that owns it." +icon: "circle-question" +keywords: ["FAQ", "common questions"] +--- + +These are the questions people ask in their first week with Cortex, answered in a sentence or two. +Every answer links to the page that covers the subject properly, so treat this as a switchboard +rather than a reference. + +Where the honest answer is "not yet", it says so. Cortex is in beta, several controls are drawn +before they are wired, and this page would be useless if it papered over that. + +## Accounts and access + +<AccordionGroup> + <Accordion title="Do I need an account to use Cortex?"> + Not for Cortex Chat. A guest can ask questions straight away, within a message allowance shown + above the composer. Cortex Code, Cortex Bot, Cortex Design, the desktop apps and the Cortex CLI + all need a signed-in account. See [Accounts and sign-in](/getting-started/accounts). + </Accordion> + <Accordion title="What happens to my guest chats when I sign in?"> + Signing in does not navigate away, and the conversation on screen is kept. Guest conversations + otherwise live in the browser session only, so sign in before you close the tab if you want to + keep them. See [Accounts and sign-in](/getting-started/accounts). + </Accordion> + <Accordion title="How do I sign in?"> + In the dialog on `cortex.foundation`, choose **Continue with Google**, **Continue with Apple**, + **Continue with email** for a code sent to your address, or **Single sign-on (SSO)** if your + organisation uses one. See [Accounts and sign-in](/getting-started/accounts). + </Accordion> + <Accordion title="Why does Cortex Code or Cortex Bot show a dialog instead of opening?"> + Two different gates. **This space is reserved** means you are a guest and these are member + surfaces, so sign in or continue in Chat. **In closed beta** means you are signed in but not + yet invited, and only **Continue in Chat** is offered. See + [Which product do I need?](/getting-started/choose-a-product). + </Accordion> + <Accordion title="Do I have to set up two-factor authentication?"> + Only if you want to export or delete your data: both actions require an enrolled authenticator + app and a recent confirmation. Cortex uses an authenticator app, with no SMS option and no + security-key option. See [Two-factor authentication](/getting-started/two-factor). + </Accordion> +</AccordionGroup> + +## Plans, quotas and billing + +<AccordionGroup> + <Accordion title="What do the plans cost?"> + Free is $0 a month, Go is $8 a month, Plus is $20 a month, and Pro is quoted rather than priced + on the page. A guest has its own allowance while signed out. See + [Plans and quotas](/getting-started/plans). + </Accordion> + <Accordion title="What actually counts against my quota?"> + Two windows are enforced: messages today and messages this month. Every turn charges both, and + whichever runs out first is the one that stops you. Tools, reasoning, web search and code runs + are not metered on any plan. See [Limits and quotas](/reference/limits). + </Accordion> + <Accordion title="How many messages do I get?"> + A guest gets 100 a day and 500 a month, Free gets 500 a day and 3,000 a month, Go gets 1,000 a + day and 8,000 a month, and Plus and Pro have no message ceiling. See + [Plans and quotas](/getting-started/plans). + </Accordion> + <Accordion title="Does unused allowance roll over?"> + No. Each window starts from zero when it rolls over, and a guest allowance does not carry into + the Free plan when you sign in. See [Plans and quotas](/getting-started/plans). + </Accordion> + <Accordion title="What do I see when I run out?"> + A **Plan limit reached** notice saying you have used everything this plan allows in the current + window, with a **Resets in** line and, sometimes, the offer of a model that is still available + under the limit. It fails closed rather than quietly degrading the answer. See + [quota_exceeded](/problems/quota_exceeded). + </Accordion> + <Accordion title="Can I change plan or pay in the product?"> + Not on this deployment. The plan cards are there and comparable, but the action carries a + **HOLD** badge instead of a payment form, and **Billing history** always reads that there are no + invoices yet. See [Plans and quotas](/getting-started/plans). + </Accordion> +</AccordionGroup> + +## Privacy and your data + +<AccordionGroup> + <Accordion title="Are my conversations used to train models?"> + No. The **Improve the model** control is off, and it is not available yet in any case, so + nothing is sampled for training without it. See + [Data and privacy](/getting-started/data-and-privacy). + </Accordion> + <Accordion title="Can I get a copy of everything?"> + Yes, from **Settings** and then **Data & privacy**, under **Your data**. **Export my data** + downloads a JSON file with your account details, conversation metadata, memories and Library + file metadata. It does not contain message bodies or the file bytes themselves, and it needs an + authenticator confirmation. See [Data and privacy](/getting-started/data-and-privacy). + </Accordion> + <Accordion title="Can I delete my account for good?"> + Yes. **Delete all data** schedules a real erasure of your account, conversations, memories, + files, bots and canvases after a 30-day grace period. Signing in again before that runs cancels + the request; afterwards nothing can be restored. See + [Data and privacy](/getting-started/data-and-privacy). + </Accordion> + <Accordion title="What does Cortex remember between chats?"> + Standing preferences and facts you share, kept as memory so answers get more personal. You can + search, edit and delete individual memories, set how long they are kept, or turn memory off + entirely. Temporary chats never read or write memory. See [Memory](/chat/memory). + </Accordion> + <Accordion title="Does Cortex honour a Global Privacy Control signal?"> + Yes. If your browser sends one, optional analytics stay off, the banner confirms the signal was + honoured instead of asking again, and the signal wins over an "allow" sent from the page. See + [Data and privacy](/getting-started/data-and-privacy). + </Accordion> +</AccordionGroup> + +## Using the product + +<AccordionGroup> + <Accordion title="Which models can I use?"> + Three are public: **Cortex 1 Mini**, **Cortex Teutonic-1**, and **Cortex-Image-1** for images in + Chat. All three are marked preview, and all three are available from the Free plan upwards. + No model is behind a paid plan today, and Cortex does not quietly answer with a different model + from the one you chose, because no fallback is configured. See [Models](/reference/models). + </Accordion> + <Accordion title="Can I use Cortex in my language?"> + The interface comes in eight languages, chosen under **Settings** and then **General**. English + is unprefixed and every other language is a URL prefix. Model prompts stay in English and the + product names are never translated. See [Interface language](/getting-started/language). + </Accordion> + <Accordion title="Where are the settings?"> + Settings is an overlay, not a page: it opens over Chat, Code or Bot and closing it returns you + to exactly where you were. Seven tabs sit in two groups, and the search field at the top of the + rail searches rows across every tab. See [Settings](/getting-started/settings). + </Accordion> + <Accordion title="What are the keyboard shortcuts?"> + Press `⌘ /`, or `Ctrl /`, for the in-product sheet. The published set is short on purpose. See + [Keyboard shortcuts](/getting-started/keyboard-shortcuts). + </Accordion> + <Accordion title="How do I know whether Cortex is down?"> + Check [System status](/reference/status). If everything fails at once rather than one action, + look there before filing anything. + </Accordion> + <Accordion title="How do I report a bug?"> + From inside the product: the **Report a bug** control beside **Settings**, or the row in + **Settings** and then **General**. It needs an account. See + [Report a bug](/getting-started/report-a-bug). + </Accordion> +</AccordionGroup> + +## Not available yet + +<AccordionGroup> + <Accordion title="Can I invite my team or share a workspace?"> + Not yet. Cortex is per account today: there are no invitations and no shared workspace, and the + role and directory rows in Settings describe an organisation you cannot create yet. + </Accordion> + <Accordion title="Can I get an API key and call Cortex from my own code?"> + Not yet. The **API keys** section is reserved rather than live, and create, rotate and revoke + stay disabled. See [Data and privacy](/getting-started/data-and-privacy). + </Accordion> + <Accordion title="Can I use a passkey, or keep recovery codes?"> + Not on this deployment. Both controls are drawn and both say so when you choose them, so an + authenticator app is the only second factor today. See + [Two-factor authentication](/getting-started/two-factor). + </Accordion> + <Accordion title="Can I stop Cortex keeping my chat history?"> + Not yet. **Save chat history** is on and cannot be changed, and it is marked as coming soon. You + can still delete individual chats, or everything, at any time. See + [Data and privacy](/getting-started/data-and-privacy). + </Accordion> + <Accordion title="Is Cortex certified against SOC 2, GDPR or HIPAA?"> + No, and Cortex does not claim to be. The **Compliance** section lists each framework's real + status, and product copy never claims a certification until an attestation exists. See + [Security and privacy](/reference/security-and-privacy). + </Accordion> + <Accordion title="Why is my account activity list empty?"> + The events are recorded, but on some deployments the list cannot be read back yet, and it says + so rather than showing you an empty table as though nothing happened. See + [Data and privacy](/getting-started/data-and-privacy). + </Accordion> +</AccordionGroup> + +## Related + +- [Quickstart](/getting-started/quickstart) for a first answer in a few minutes. +- [Which product do I need?](/getting-started/choose-a-product) for picking a surface. +- [Plans and quotas](/getting-started/plans) for the ladder and the windows. +- [Troubleshooting](/getting-started/troubleshooting) for what a message means. +- [Glossary](/getting-started/glossary) for the words this site uses. diff --git a/getting-started/glossary.mdx b/getting-started/glossary.mdx new file mode 100644 index 0000000..f36b507 --- /dev/null +++ b/getting-started/glossary.mdx @@ -0,0 +1,85 @@ +--- +title: "Glossary" +description: "The Cortex words you meet across this site, in alphabetical order, each with a link to the page that owns it." +icon: "book" +keywords: ["terminology", "definitions", "vocabulary"] +--- + +Cortex uses a small vocabulary consistently, and most of it is ordinary English used precisely. This +page collects the words you will meet on other pages of this site, in alphabetical order, with one +or two sentences each and a link to the page that explains the thing properly. + +Only words the product actually uses are listed here. The application names themselves are not in +the list: Cortex Chat, Cortex Code, Cortex Bot, Cortex Design, Cortex Security, the Cortex CLI and +Cortex Bounty each have their own section of the site. + +## A to C + +| Term | What it means | +| --- | --- | +| **Activity** | The record of what happened on your account across Chat, Code and Bot, covering sign-ins, connector changes, exports and approvals over the last 30 days. See [Data and privacy](/getting-started/data-and-privacy). | +| **Appshots** | A desktop-only capture of the last Chat or Code thread you used, taken with a double tap of a modifier key. The web app has no global hotkey. See [Cortex desktop app](/getting-started/desktop). | +| **Approval matrix** | The grid in **Settings** where you choose **Ask** or **Always ask** for each kind of action, read, edit, shell and pay, on Chat, Code and Bot. Pay always asks. See [Permissions and approvals](/code/approvals). | +| **Artifact** | Something Cortex produced that is kept in its own place rather than only inside a transcript. The sidebar collects them under **Artifacts**. | +| **Canvas** | A document surface you keep and work on, rather than a message in a conversation. Chat and Cortex Design each have their own. See [Chat canvases](/chat/canvases) and [Design canvases](/design/canvases). | +| **Closed beta** | A product that is open only to invited accounts. A signed-in account that has not been invited sees a gate and can continue in Chat. See [Accounts and sign-in](/getting-started/accounts). | +| **Command palette** | The jump-anywhere panel in Cortex Code, opened with `⌘ K` or `Ctrl K`. See [Keyboard shortcuts](/getting-started/keyboard-shortcuts). | +| **Connector** | A connected app whose tools join your conversations, so Cortex can act on that app instead of only talking about it. See [Connectors](/chat/plugins). | + +## E to M + +| Term | What it means | +| --- | --- | +| **Entitlement** | A capability that a plan includes. When your plan does not include one, Cortex says **Not included in your plan**. See [entitlement_required](/problems/entitlement_required). | +| **Global Privacy Control** | A signal some browsers send to refuse optional tracking. Cortex honours it: optional analytics stay off and the signal wins over an "allow" sent from the page. See [Data and privacy](/getting-started/data-and-privacy). | +| **Grace period** | The 30 days between requesting deletion of your data and the erasure actually running. Signing in again during that time cancels the request. See [Data and privacy](/getting-started/data-and-privacy). | +| **Guest** | Someone using Chat without signing in. A guest has a message allowance for the browser session and cannot create anything it would later need to come back and revoke. See [Accounts and sign-in](/getting-started/accounts). | +| **Library** | Where Chat keeps the files you upload and the files it produces. The storage meter under **Plan & billing** measures it. See [Library](/chat/library). | +| **Mascot** | Another word the product uses for a bot, most visibly when Cortex asks whether your mascots may use your connected tools. See [Cortex Bot](/bot). | +| **MCP server** | A Model Context Protocol server you attach over HTTP so its tools join the model in your conversations. See [MCP servers](/chat/mcp-servers). | +| **Member** | A signed-in Cortex account. Everything beyond guest Chat is member territory. See [Accounts and sign-in](/getting-started/accounts). | +| **Memory** | Standing preferences and facts you have shared, kept so answers get more personal over time. Reviewable, deletable, and switchable off. See [Memory](/chat/memory). | +| **Mode** | Chat, Code and Bot are modes of one shell. Switching mode keeps the shell and the sidebar in place rather than loading a different application. See [What is Cortex](/getting-started/what-is-cortex). | + +## O to R + +| Term | What it means | +| --- | --- | +| **Overlay** | A dialog that opens over the product instead of navigating away from it. Settings is the one you meet most. See [Settings](/getting-started/settings). | +| **Plan** | The named ceiling on what an account may use in a window. The ladder is Guest, Free, Go, Plus and Pro. See [Plans and quotas](/getting-started/plans). | +| **Preview** | A label on a live model whose name and behaviour are not final. Every public Cortex model carries it today. See [Models](/reference/models). | +| **Problem code** | The stable identifier attached to every failure, such as `quota_exceeded` or `forbidden`. Each one has its own page. See the [problem catalog](/problems). | +| **Project** | A container for related chats and files, with custom instructions of its own that can override your account instructions. Your plan caps how many you may have. See [Projects](/chat/projects). | +| **Quota** | A count that resets on a fixed window, such as messages today or messages this month. See [Limits and quotas](/reference/limits). | +| **Reference id** | The identifier printed on a failure card. Quote it in a bug report and the team can find the exact request. See [Errors](/reference/errors). | +| **Reserved space** | A member-only product that a guest has opened. The dialog offers to sign you in, or to continue in Chat. See [Accounts and sign-in](/getting-started/accounts). | +| **Routine** | A repeatable job you set up in Cortex Bot. Routines belong to your account and follow you across devices. See [Routines](/bot/routines). | +| **Runtime** | The isolated computer a Cortex Code session runs in. See [Cloud runtimes](/code/runtimes). | + +## S to W + +| Term | What it means | +| --- | --- | +| **Scheduled task** | A Chat task that runs on a schedule rather than when you ask. Cortex notifies you after one has run. See [Scheduled tasks](/chat/scheduled-tasks). | +| **Session** | A unit of work in Cortex Code, started with **New session** and kept as its own thread of changes. See [Code sessions](/code/sessions). | +| **Shortcut sheet** | The in-product list of keyboard chords, opened and closed with `⌘ /` or `Ctrl /`. It lists only chords that are actually bound. See [Keyboard shortcuts](/getting-started/keyboard-shortcuts). | +| **Single sign-on (SSO)** | Signing in through your organisation's identity provider instead of a personal account. See [Accounts and sign-in](/getting-started/accounts). | +| **Skill** | A reusable capability you add to a product. Chat, Cortex Bot and the CLI each document their own: [Skills in Chat](/chat/skills), [Bot skills](/bot/skills), [Skills in the CLI](/cli/skills). | +| **Step-up confirmation** | Re-entering your authenticator code before a sensitive action such as an export or a deletion. A confirmation lasts fifteen minutes and covers only the session that asked for it. See [Two-factor authentication](/getting-started/two-factor). | +| **Temporary chat** | A conversation that neither reads nor writes memory. See [Conversations](/chat/conversations). | +| **Window** | The period a quota counts over, a day or thirty days. Windows are fixed rather than rolling, and the product shows a **Resets in** line instead of a wall-clock time. See [Plans and quotas](/getting-started/plans). | + +## Words that belong to one product + +Some vocabulary is specific enough that it is defined where it is used rather than here: tickets and +environments in Cortex Code, channels and tasks in Cortex Bot, checks and review policy in Cortex +Security, and hooks, agents and themes in the Cortex CLI. Each product's own pages carry those +definitions, and the [Related](#related) links below are the fastest way in. + +## Related + +- [What is Cortex](/getting-started/what-is-cortex) for the applications and how they fit together. +- [Which product do I need?](/getting-started/choose-a-product) for picking one. +- [Plans and quotas](/getting-started/plans) for plans, quotas and windows. +- [Frequently asked questions](/getting-started/faq) for the short answers. +- [Troubleshooting](/getting-started/troubleshooting) for what a message in the product means. diff --git a/getting-started/keyboard-shortcuts.mdx b/getting-started/keyboard-shortcuts.mdx new file mode 100644 index 0000000..e9eedb1 --- /dev/null +++ b/getting-started/keyboard-shortcuts.mdx @@ -0,0 +1,112 @@ +--- +title: "Keyboard shortcuts" +description: "The chords the Cortex web app really binds, where each one works, and which surfaces have no shortcuts of their own." +icon: "keyboard" +keywords: ["hotkeys", "chords", "shortcut sheet"] +--- + +Cortex binds a small, deliberate set of keyboard chords in the web app. The product keeps that set +short on purpose: a chord is only listed once something is wired to it, so a key you read here does +something when you press it. + +This page is the published set. It covers the in-product shortcut sheet, the chords that work in +Cortex Chat and Cortex Code, the composer keys, why nothing fires while you are typing, and the +surfaces that have no shortcuts yet. + +## Open the shortcut sheet + +Press `⌘ /` on a Mac, or `Ctrl /` on Windows and Linux, to open and close the sheet from anywhere +in the app. The sheet groups its rows under **Navigation**, **Conversation**, **Composer** and +**Mode-specific**, in that order, and it hides a group that has no rows. That is why you never see +a **Composer** group: no composer chord is bound, so the heading is not drawn. + +The sheet also filters itself by the mode you are in. The `⌘ /` row is there in every mode; Cortex +Chat adds its search and stop-response rows, Cortex Code adds the command palette, and in Cortex Bot +only the `⌘ /` row is shown. + +## Every chord the web app binds + +Modifiers render for your platform: the command key shows as `⌘` on a Mac and `Ctrl` everywhere +else, and shift shows as `⇧` on a Mac and `Shift` everywhere else. + +| Action | Mac | Windows and Linux | Where it works | +| --- | --- | --- | --- | +| Open or close the shortcut sheet | `⌘ /` | `Ctrl /` | Anywhere in the app | +| **Search** | `⌘ K` | `Ctrl K` | Cortex Chat | +| Command palette | `⌘ K` | `Ctrl K` | Cortex Code | +| **Stop response** | `Esc` | `Esc` | Cortex Chat | +| Show or hide the sidebar | `⌘ \` | `Ctrl \` | Anywhere in the app | + +The same chord can mean two things in two products: `⌘ K` opens **Search** in Chat and the command +palette in Code. The short list inside **Settings** labels `⌘ K` as **New chat**; what the chord +actually opens is Search in Chat and the palette in Code, so treat it as a jump-anywhere key rather +than a create key. + +<Note> +Neither list in the product is complete. The shortcut sheet carries four rows and leaves out +`⌘ \`, which **Settings** advertises and the app binds. The table above is the union of both, so it +is longer than what either surface shows you. +</Note> + +## Composer keys + +Sending and editing a message are behaviours of the composer rather than entries in the shortcut +sheet, and they work the same way everywhere you type to Cortex. + +| Key | What it does | +| --- | --- | +| `Enter` | Sends the message | +| `Shift` `Enter` | Starts a new line without sending | +| `Esc` | Stops a response that is still streaming | + +## Nothing fires while you are typing + +Every chord declines while the text caret is inside an input, a text area, a select or any editable +region. Typing a `/` in a message never opens the shortcut sheet, and typing a `\` never collapses +the sidebar. + +Two more keys behave as you would expect: `Esc` closes the mobile navigation drawer, and `Enter` or +`Esc` closes the sign-in confirmation dialog rather than waiting for it to close on its own. Hiding +the sidebar is a layout change only, so your conversation list and its scroll position are still +there when you bring it back. + +## Chords that were removed, and surfaces with none + +Cortex would rather show you a shorter list than a key that does nothing. + +- Older documentation published **Focus composer** (`⇧ Esc`) and **Copy last answer** (`⌘ ⇧ C`). + Neither is bound today. They were taken out of the product's own list instead of being left as + dead chords. +- **New session** and **New bot** exist as labels in the product but have no chord behind them. + Start them from the sidebar instead. +- Cortex Bot shows only the shortcut-sheet chord. There is nothing else to learn there yet. +- Cortex Design and Cortex Security have no keyboard shortcuts of their own. Nothing is hidden; + there is simply nothing to list. + +## Shortcuts outside the web app + +<CardGroup cols={2}> + <Card title="Cortex desktop app" icon="desktop" href="/getting-started/desktop"> + The desktop app adds the Appshots capture chord, a double tap of the command key on a Mac or a + double tap of `Alt` on Windows. That chord lives on the desktop app; the web has no global + hotkey. + </Card> + <Card title="CLI keyboard shortcuts" icon="terminal" href="/cli/keyboard"> + The terminal interface has its own keys, documented with the Cortex CLI rather than here. + </Card> +</CardGroup> + +## Find the list inside the product + +Open **Settings** from the sidebar footer and stay on **General**. The **Keyboard shortcuts** row, +described as "Work faster without leaving the keyboard", lists a couple of chords and carries a +button that opens the full sheet. You can also press `⌘ /` from wherever you are and skip Settings +altogether. + +## Related + +- [Settings](/getting-started/settings) for the tab that holds the shortcuts row. +- [Conversations](/chat/conversations) for what Search and Stop response act on. +- [Code sessions](/code/sessions) for the surface the command palette belongs to. +- [CLI keyboard shortcuts](/cli/keyboard) for the terminal keys. +- [Cortex desktop app](/getting-started/desktop) for the desktop-only capture chord. diff --git a/getting-started/language.mdx b/getting-started/language.mdx new file mode 100644 index 0000000..345e51d --- /dev/null +++ b/getting-started/language.mdx @@ -0,0 +1,79 @@ +--- +title: "Interface language" +description: "The eight languages Cortex is translated into, how to switch, what stays in English, and how the language prefix in the address bar works" +icon: "language" +--- + +The Cortex interface is translated into eight languages. Switching language changes the labels, buttons, menus and messages you see; it does not change how you talk to the models, and it does not change the product names. English is the source of truth for every string, so every other language is a translation of it. + +This page lists the eight languages and their URL prefixes, shows how to switch, explains how Cortex chooses a language on your first visit, and says exactly what stays in English. + +## The eight languages + +| Language | Shown in the picker | URL prefix | +| --- | --- | --- | +| English | `English` | none, the URL stays unprefixed | +| French | `Français` | `/fr` | +| Spanish | `Español` | `/es` | +| German | `Deutsch` | `/de` | +| Japanese | `日本語` | `/ja` | +| Simplified Chinese | `简体中文` | `/zh-Hans` | +| Brazilian Portuguese | `Português (Brasil)` | `/pt-BR` | +| Korean | `한국어` | `/ko` | + +`zh-Hans` and `pt-BR` are single prefixes. They are never shortened to `zh` or `pt`. + +## Change your language + +<Steps> +<Step title="Open Settings"> +Choose **Settings** in the sidebar footer. Settings opens as an overlay over Chat, Code or Bot, so you keep your place. +</Step> +<Step title="Stay on General"> +**General** is the first tab and the one Settings opens on. +</Step> +<Step title="Pick a language"> +Under **Language** (`Interface language. Model prompts stay in English.`) choose one of the eight entries. +</Step> +<Step title="Check the address bar"> +The interface reloads in that language and the address bar gains the matching prefix, for example `/fr/code`. English has no prefix, so choosing English removes it. +</Step> +</Steps> + +Choosing a language here records the choice and Cortex remembers it for a year. Picking a language is a deliberate act, so from then on it outranks whatever your browser asks for. + +## How Cortex picks a language the first time + +On your first visit Cortex reads your browser's language once. If it is not English, you are moved to the matching prefix and that choice is remembered. After that first read, your remembered choice wins and the browser header is not consulted again. + +Opening a prefixed URL directly, for example a link someone sent you at `/es/bot`, shows that language for the visit without changing your saved preference. So a Spanish link does not switch you to Spanish for good, and returning to Cortex on your own gives you your own language back. + +The prefix is preserved as you move around: navigation inside the app, a reload and a new tab all stay in the language you are reading. Search engines are never redirected by language. A crawler sees the URL it asked for. + +<Note> +English is unprefixed on purpose. `/en` and `/en/...` redirect to the URL without the prefix, so `/en/code` becomes `/code`. Do not bookmark an `/en` URL, bookmark the plain one. +</Note> + +## What stays in English + +Three things do not follow the interface language. + +**Model prompts.** The instructions Cortex sends to a model stay in English, which is what the **Language** row means by `Model prompts stay in English.` The setting governs the interface, not the conversation. + +**Product names.** **Cortex**, **Cortex Chat**, **Cortex Code**, **Cortex Bot** and **Cortex Security** are never translated. A French interface still says Cortex Chat. + +**These documentation pages.** `docs.cortex.foundation` is written in English. The eight languages apply to the application at `cortex.foundation`. + +## If you cannot find the setting + +The **Language** row is on **General**, between **Theme** and **Answer font**. If you land on another tab, use **Search settings** at the top of the left rail. It searches rows across every tab, not just the one you are on, and jumps to the row when you pick a result. A search with no match answers `No settings match "{query}"` with the hint `Try a shorter word, or clear the search to browse all tabs.` + +You can also open Settings straight on the tab you want: `cortex.foundation/settings` opens it over Chat, and an unknown tab in the address falls back to **General**, which is where **Language** lives anyway. + +## Related + +- [Settings](/getting-started/settings) +- [Accounts and sign-in](/getting-started/accounts) +- [What is Cortex](/getting-started/what-is-cortex) +- [Keyboard shortcuts](/getting-started/keyboard-shortcuts) +- [Troubleshooting](/getting-started/troubleshooting) diff --git a/getting-started/notifications.mdx b/getting-started/notifications.mdx new file mode 100644 index 0000000..49fd976 --- /dev/null +++ b/getting-started/notifications.mdx @@ -0,0 +1,93 @@ +--- +title: "Notifications" +description: "One notification inbox for Chat, Code and Bot: what Cortex tells you about, what the dot on the bell means, and how rows are marked read" +icon: "bell" +--- + +Cortex has one notification inbox for the whole product. The bell sits in the sidebar header next to the Cortex wordmark, and the panel it opens covers Cortex Chat, Cortex Code and Cortex Bot together. There is no separate bell per product, so switching mode does not change what is in the list. + +This page covers what Cortex notifies you about, how the panel behaves when you open it, what the badge on the bell does and does not tell you, and where a row takes you when you choose it. + +## Open the panel + +The bell is labelled **Notifications**. When something is unread, its accessible name becomes `{count} unread notifications`, so a screen reader hears the count even though the badge does not show one. + +Choosing the bell opens a dialog titled **Notifications**. Its lede is `Everything Cortex has told you about, newest first.` when nothing is unread, and `{count} unread, newest first.` when something is. Rows are ordered newest first. + +Opening the panel refreshes the list without blanking the rows already on screen, so the list does not flicker while it reloads. + +## What Cortex notifies you about + +One kind of row per thing Cortex has to tell you. The label in the middle column is the word the row carries. + +| What happened | Row label | Where it comes from | +| --- | --- | --- | +| A scheduled Chat task ran | `scheduled task` | Cortex Chat | +| Something mentioned you | `mention` | A conversation | +| A Cortex Code run finished | `code run finished` | Cortex Code | +| A Cortex Code run is waiting on a decision | `code run needs you` | Cortex Code | +| A bot parked a step for approval | `bot needs you` | Cortex Bot | +| A bot's computer failed to wake | `computer could not start` | Cortex Bot | +| Anything the app does not recognise | `notification` | Fallback label | + +That list is the whole surface. Cortex notifies you when a run finishes, when it needs a decision from you, and when an automation ran, which is exactly what the empty state promises. + +## Read and clear notifications + +<Steps> +<Step title="Open the bell"> +Choose **Notifications** in the sidebar header. The rows you can see are marked read as the panel opens, so you do not have to click each one. +</Step> +<Step title="Clear the rest"> +Choose **Mark all read**. The button is only drawn while something is unread, so its absence means there is nothing left to clear. +</Step> +<Step title="Act on a row"> +Choose a row to open what it refers to. A finished or blocked Code run opens its session, a mention opens the conversation, and a bot row opens the bot. A row with no subject to open is a plain button rather than a link. +</Step> +</Steps> + +If marking read fails, Cortex says so beside the button with `They could not be marked read` and the row simply stays unread. Nothing is silently swallowed. + +## What the dot means + +The badge is a small dot. It is never a number. + +| Panel state | Badge on the bell | +| --- | --- | +| Loading | No badge | +| Failed to load | No badge | +| Nothing unread | No badge | +| Something unread | A dot | + +Loading and failure both render no badge on purpose: a dot on a list that could not be loaded would be a claim Cortex cannot back. The unread count is exposed only through the bell's accessible label. + +## When the panel is empty or will not load + +| What you see | What it means | +| --- | --- | +| Skeleton rows and no badge | The list is still loading | +| An error block with **Retry** | The list could not be loaded. Choose **Retry** | +| `Nothing yet` / `Cortex tells you when a run finishes, when it needs a decision, and when an automation ran.` with **Start a chat** | You have no notifications at all | +| `They could not be marked read` | The read write failed; the rows stay unread | + +<Note> +A failed list is not an empty list. When the panel shows an error block, assume you may have unread rows and try again rather than reading the absence of a dot as "nothing to see". +</Note> + +## Related surfaces + +The inbox is not the only place Cortex reports on itself, and some of what you might expect from a notification lives elsewhere: + +- **Approvals** and **Pending approval** in the sidebar collect decisions that are waiting on you, and `bot needs you` and `code run needs you` rows point at the same work. +- **Activity** records what happened on the account, rather than telling you about it. Review it under **Settings → Data & privacy → Activity**. +- **Scheduled** lists Chat schedules, the automations behind `scheduled task` rows. + +Notification behaviour in the Cortex desktop app is a separate surface from this panel and is covered with the desktop app rather than here. One email notification is described in Settings and is not available yet: **Login alerts** (`Email when a new device or location signs in.`) is drawn but disabled, with `Login alerts are not available on this account yet.` + +## Related + +- [Code notifications](/code/notifications) +- [Inbox](/bot/inbox) +- [Scheduled tasks](/chat/scheduled-tasks) +- [Data and privacy](/getting-started/data-and-privacy) +- [Cortex desktop app](/getting-started/desktop) diff --git a/getting-started/plans.mdx b/getting-started/plans.mdx index e6ae2ed..9d409fc 100644 --- a/getting-started/plans.mdx +++ b/getting-started/plans.mdx @@ -1,71 +1,132 @@ --- title: "Plans and quotas" -description: "Guest, Free, Go, Plus, and Pro as listed in Settings → Plan & billing. Quotas fail closed and tell you when they reset." -keywords: ["pricing", "quotas", "limits", "billing", "Free", "Go", "Plus", "Pro"] +description: "Guest, Free, Go, Plus and Pro: the message windows each plan allows, what the app draws as a meter, and how a limit fails." +icon: "credit-card" --- -Your plan, today's usage, and the reset timers live under **Settings → Plan & billing**. The product is the source of truth for numbers; this page explains what each plan is for and how limits behave. +A plan in Cortex is a named ceiling on a fixed window. Two windows are counted on every turn you send: **messages today** and **messages this month**. A turn charges both, and whichever runs out first is the one that stops you. Your plan, your usage and the reset countdowns live in **Settings → Plan & billing**. -<Frame caption="Settings → Plan & billing. The plan ladder as shown in the product; the Change plan buttons are marked Coming soon while checkout is being finished."> - <img src="/images/product/settings-plans.png" alt="Plan & billing — Free, Go, Plus, and Pro plan cards with their features" /> -</Frame> +This page lists the five plans as the product lists them, the message ceilings on each, the other entitlements that exist behind the scenes, what the app actually draws as a meter, and what a limit looks like when you reach it. The product is always the source of truth for a number you are about to rely on. ## The plans -| Plan | Price | Who it is for | Includes | -| --- | --- | --- | --- | -| **Guest** | — | Anyone before signing in | A daily and monthly message allowance; conversations live in the browser session | -| **Free** | $0 / month | Everyday tasks | Limited messages each day and month · Cortex 1 Mini · web search and code runs · image generation with Cortex-Image-1 · written conversations, subject to abuse protection | -| **Go** | $8 / month | Everyday work | Everything in Free · more messages each day and month · priority when the fleet is busy · extended memory and context | -| **Plus** | $20 / month | Advanced intelligence | Everything in Go · more messages and higher ceilings · projects and saved work · extended memory and context · early access to new features | -| **Pro** | Custom | People who live in Cortex | Everything in Plus · unlimited messages · SSO, audit export, and private routing · team workspace and admin controls · preview access to new features | +| Plan | Price | What the product says it is for | +| --- | --- | --- | +| **Guest** | Not sold | `Try Cortex without an account.` | +| **Free** | $0 / month | `Intelligence for everyday tasks.` | +| **Go** | $8 / month | `Extended access for everyday work.` | +| **Plus** | $20 / month | `Go further with advanced intelligence.` | +| **Pro** | Quote only, shown as `Custom` | `Maximum access for people who live in Cortex.` | + +**Plus** is marked `RECOMMENDED` in the product. Guest is not listed on the pricing cards: it is the allowance you get before you sign in, and the card simply reads `Guest allowance while signed out.` **Pro** is quote-only, so its price shows as `Custom` rather than an amount. + +Three capabilities are reserved for **Pro**: single sign-on, audit log export and private model routing. When a plan does not include something at all, Cortex answers `Not included in your plan` rather than metering you down to zero. + +## Message quotas + +| Plan | Messages today | Messages this month | +| --- | --- | --- | +| Guest | 100 | 500 | +| Free | 500 | 3,000 | +| Go | 1,000 | 8,000 | +| Plus | Unlimited | Unlimited | +| Pro | Unlimited | Unlimited | + +The daily window is 24 hours and the monthly window is 30 days. Both are fixed rather than rolling: each window has a start, and the counter returns to zero when the window rolls over. The product never prints a wall-clock reset time; it shows `Resets in {label}` instead. Unused allowance does not roll over into the next window. + +**Unlimited** here means there is no ceiling to hit, not a very large number. Quotas **fail closed**: when a window is used up Cortex says so and shows when it resets, rather than quietly shortening the answer. + +<Note> +The guest allowance belongs to the browser session, not to an account. It ends when you sign in and does not carry over, and the Free plan's windows start fresh on the account. See [Accounts and sign-in](/getting-started/accounts). +</Note> + +## Other ceilings -**Plus** is the recommended plan in the product. Switching takes effect at the next billing cycle. At the time of writing the **Get Free / Go / Plus / Pro** buttons and **Billing history** are marked **Coming soon**; the ladder above is what the product lists. +These entitlements exist on the plans and shape what Cortex lets you do, even though most of them are not drawn as meters. -## Usage and reset timers +| Ceiling | Guest | Free | Go | Plus | Pro | +| --- | --- | --- | --- | --- | --- | +| Projects | None | 3 | 5 | Unlimited | Unlimited | +| Attachment size (`File storage`) | None | 10 MB | Not published | 10 MB | 10 MB | +| Library storage | 200 MB | 500 MB | Not published | 20 GB | Unlimited | +| `Images today` | 2 | 15 | Not published | 100 | Unlimited | +| `Exports today` | 2 | 15 | Not published | 100 | Unlimited | +| `Parallel agents` | Not published | 1 | Not published | 10 | 50 | -**Settings → Plan & billing** shows today's and this month's message counts with a reset countdown for each window. +Reading the table: -<Frame caption="A guest's usage: 100 messages today and 500 this month, each with its own reset timer."> - <img src="/images/product/settings-plan-usage.png" alt="Guest plan usage — messages today 0 of 100, messages this month 0 of 500, with reset timers" /> -</Frame> +- **None** means forbidden, not unlimited. A guest has no projects and cannot upload files. +- **Attachment size hardly varies.** Paying more does not raise it: where a plan can attach at all, the ceiling on a single file is 10 MB, which is why the plans that can upload all show the same number. A larger plan buys you more room in the Library, not bigger files. Go is the one plan this page will not print a figure for. +- **Not published** means this page has no figure it can responsibly print for the Go plan, so it will not invent one. Check **Settings → Plan & billing** on a Go account for what it actually allows. +- **Parallel agents** is a plan attribute that the product displays but does not currently enforce, so read those numbers as what the plan records rather than as what will stop you. The matching error code exists regardless, so handle it rather than assuming it can never arrive. -## How limits fail +## What is not metered -Cortex quotas **fail closed**: when a window is used up, the product says so and tells you when it resets. Nothing is silently downgraded, and there is no paywall pretending to be a quota. +Reasoning, code runs in the sandbox and web searches are **not metered on any plan**, Guest included. If you read older copy promising "five reasoning runs a day" or "fifty web searches a day", that copy is stale. Those counters were retired. -| What happened | Error code | What to do | +No plan carries a file-retention window either. Conversations, Chat Library files and Design canvases you still hold are not deleted on a plan timer; they stay until you delete them. See [Data and privacy](/getting-started/data-and-privacy) for what Cortex does prune, and on what schedule. + +## What you can actually see + +Three things are drawn as meters on the plan cards, in the form `{used} / {limit}` with `Resets in {label}` underneath: **Messages today**, **Messages this month** and **Projects**. Every other entitlement is suppressed from the cards, so do not go looking for an images meter or a web-search meter. The tab notes this itself: `Quota bars on this tab come from the plan, not a certificate.` + +Elsewhere in **Settings → Plan & billing** you also get: + +| Section | What it shows | +| --- | --- | +| `STORAGE` | Library usage, with a `Manage` link that opens Library. Failure shows `Storage usage could not be loaded` and a `Retry`. | +| Current plan | `{name} plan`, the price, and a `CURRENT PLAN` badge | +| `Usage` | Tokens this account used, split across Cortex Chat, Cortex Code, Cortex Bot and `Unattributed`, over a `7 days`, `30 days` or `90 days` window, `Per day` or `PER MODEL`. Empty windows stay zeros. | +| `Billing history` | Columns `DATE`, `DESCRIPTION`, `AMOUNT`, `STATUS` | + +The sidebar carries the same information in miniature: a plan chip reading `{name} plan` and a quota chip reading `{used} of {limit} {quota}`. + +## When you reach a limit + +Cortex has a dedicated notice for this, separate from a generic error card. It reads **Plan limit reached** with `You have used everything this plan allows in the current window.`, then `Resets in {label}`, `Current plan: {plan}`, and where a model is still available under the limit, `Continue with {model}`. The heading is specific to the window you exhausted, for example `You have used today's messages`, `You have used this month's messages` or `You have reached your project limit`. + +| What happened | Problem code | What to do | | --- | --- | --- | -| You used the window for today or this month | [`quota_exceeded`](/problems/quota_exceeded) | Wait for the reset shown in the product, or move to a plan with higher ceilings | -| The plan does not include the capability at all | [`entitlement_required`](/problems/entitlement_required) | That capability is not on this plan | -| Too many requests in a short burst | [`rate_limited`](/problems/rate_limited) | Retry after the pause the product suggests | -| The fleet is at capacity | [`no_capacity`](/problems/no_capacity) | Try again shortly; Go and above get priority when the fleet is busy | +| The window for today or this month is used up | [`quota_exceeded`](/problems/quota_exceeded) | Wait for the reset shown in the product, or move to a plan with higher ceilings | +| The plan does not include the capability at all | [`entitlement_required`](/problems/entitlement_required) | Compare plans under **Settings → Plan & billing** | +| Requests arrived faster than the limit allows | [`rate_limited`](/problems/rate_limited) | Pause, then retry. This clears by itself. | +| Too many runs in parallel on the account | [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Let a session or a run finish to free a slot | +| An attachment is larger than Cortex accepts | [`payload_too_large`](/problems/payload_too_large) | `Files can be at most 10 MB. Remove or shrink the attachment and try again.` | -Image generation on Free and Guest is metered as `images_per_day`. Running out is `quota_exceeded`, not a paywall. See [Image generation](/chat/images). +There is a second notice for the plan side of the same check, headed `That attachment is over your plan's size limit`. That one is raised against what your plan allows you to attach at all rather than against the 10 MB ceiling, which is why a plan that permits no attachments refuses every upload with it. -The CLI shows the same thing in the terminal: when the agent quota is exhausted the composer is held with the reset time, and `/usage` shows the details. See [CLI troubleshooting](/cli/troubleshooting). +## Changing plan -## Model availability +**Settings → Plan & billing → Change plan** lists the ladder with `Switch anytime — changes take effect at the next billing cycle.` The plan you are on reads `Current plan`; the others read `Get {plan}` or `Downgrade`. A guest sees `Sign in to change plan`. -Model availability depends on your plan. During peak hours new chats may fall back to a faster model; the composer chip always shows which model is serving the conversation. See [Models](/chat/models). +<Warning> +There is no checkout in the product today. When billing is not configured, the plan actions and `Manage billing` carry a `HOLD` badge instead of opening a payment form, `Billing history` always reads `No invoices yet — your receipts will appear here.`, and `Usage credits`, `Spend cap` and `Add credit` resolve to `Not available on this deployment` or `Not reported`. Expect to arrange a plan change outside the app for now. +</Warning> ## Frequently asked <AccordionGroup> <Accordion title="Do guest messages and Free messages share a quota?"> - No. The guest allowance belongs to the browser session and ends when you sign in. Free has its own daily and monthly limits on the account. + No. The guest allowance belongs to the browser session and ends when you sign in. Free has its own daily and monthly windows on the account, and they start fresh. </Accordion> <Accordion title="Does unused quota roll over?"> - No. Daily and monthly windows reset on the timers shown in Plan & billing. + No. Each window has a start and a length, and the counter returns to zero when it rolls over. What you did not use is not banked. + </Accordion> + <Accordion title="Which models does my plan serve?"> + Every published chat model is available from the Free plan up, so in practice no Chat model is plan-gated today and you will not meet a locked row in the picker. When a model is unavailable or a limit is reached, Cortex says so and offers what is still available rather than quietly substituting something else, and the composer always shows which model is answering. See [Models](/chat/models). + </Accordion> + <Accordion title="Is there a file-retention window on my plan?"> + No plan carries one, so the retention line never appears on the plan card. Files stay until you delete them. </Accordion> - <Accordion title="Was there a Pro trial?"> - Through 7 September 2026 a signed-in member could claim one month of Cortex Pro from the product. That window has closed; claiming twice never stacked. + <Accordion title="Was there a free month during the beta?"> + Yes, and it has closed. During the beta a banner offered signed-in accounts one free month of a paid plan, one grant per account, and claiming twice never stacked months. The offer window ended on 7 September 2026. The banner and its `Claim a free month` button are still in the build, so treat anything you see there as expired until the product says otherwise. </Accordion> </AccordionGroup> -## Next +## Related -- [Accounts](/getting-started/accounts) — guest versus member, and what each unlocks. -- [Models and thinking](/chat/models) — which models a plan can serve. -- [Image generation](/chat/images) — the `images_per_day` window. -- [CLI troubleshooting](/cli/troubleshooting) — quota messages in the terminal. +- [Accounts and sign-in](/getting-started/accounts) - guest versus member, and what an account lifts. +- [Settings](/getting-started/settings) - the Plan & billing tab among the seven tabs. +- [Limits reference](/reference/limits) - the hard numbers in one table. +- [Models](/chat/models) - the published chat models, and what Cortex does when one is unavailable. +- [`quota_exceeded`](/problems/quota_exceeded) - the problem code behind a used-up window. diff --git a/getting-started/quickstart.mdx b/getting-started/quickstart.mdx index 7ee2863..8df77c6 100644 --- a/getting-started/quickstart.mdx +++ b/getting-started/quickstart.mdx @@ -1,78 +1,93 @@ --- title: "Quickstart" -description: "Open Cortex in a browser, get a first answer from Chat, then sign in for Code, Bot, and Design." -image: "/images/banners/getting-started.png" -keywords: ["tutorial", "first steps", "getting started", "onboarding"] +description: "Open Cortex in a browser, get a first answer from Chat as a guest, then sign in and open Code, Bot, Design, Security or the CLI." +icon: "rocket" --- -Cortex is one account across four products: **Chat**, **Code**, **Bot**, and **Design**, plus a **CLI** for the terminal. This page takes you from a browser tab to a useful first session in about five minutes. +This page takes you from a browser tab to a useful first session. The first answer needs nothing but a browser: **Cortex Chat** works before you sign in. Everything that has to survive a closed tab, and every other application, needs a signed-in account. -<Frame caption="Cortex Chat home as a guest — Chat, Code, and Bot in the sidebar, the composer ready, and 100 free messages before you sign in."> - <img src="/images/product/chat-home.png" alt="Cortex Chat home — Chat, Code, and Bot in the sidebar, composer ready" /> -</Frame> +It covers what each task requires, the five steps to a first answer, how signing in changes the screen, and where to go next for the application you actually came for. ## What you need | To do this | You need | | --- | --- | -| Ask Chat a question | A browser. No account. | -| Keep projects, files, memory, and plans | A signed-in account | -| Connect apps, GitHub, or MCP servers | A signed-in account | -| Open Code or Bot | A signed-in account | -| Run Code on **This PC** or over **SSH** | The [desktop app](/getting-started/desktop) or the [CLI](/cli) | -| Edit a Design canvas | The [Design desktop app](/design/desktop) | +| Ask Cortex Chat a question | A browser. No account. | +| Keep chats, projects, Library files and memory across devices | A signed-in account | +| Attach a file to a message | A signed-in account. The size ceiling comes from your plan | +| Connect an app or an MCP server | A signed-in account | +| Open Cortex Code or Cortex Bot | A signed-in account, and a closed-beta invitation | +| Work on a Cortex Design canvas | A signed-in account and the Cortex Design desktop app | +| Run Code on your own machine, or on a server you own | The [desktop app](/getting-started/desktop) or the [CLI](/cli/index) | + +## Get a first answer <Steps> - <Step title="Open Chat"> - Go to [cortex.foundation](https://cortex.foundation). Chat is the default surface and works before you sign in. The banner above the composer shows how many free guest messages remain today. + <Step title="Open Cortex"> + Go to [cortex.foundation](https://cortex.foundation). Chat is the surface you land on, and it is the one application that is never gated. A banner above the composer counts the free messages left in the guest allowance, which is 100 a day and 500 over thirty days. </Step> - <Step title="Send a first message"> - Type in the composer and press **Enter**. The answer streams in as it is written; press **Esc** to stop a response. Try one of the suggestions under the composer, or paste a document and ask for a summary. + <Step title="Send a message"> + Type in the composer and press **Enter**. The answer streams as it is written. Press **Esc** to stop a response that is still running, and **Shift** with **Enter** for a new line instead of sending. ```text Summarize this quarterly report in five bullet points, then list three risks. ``` </Step> - <Step title="Attach a file or pick a mode"> - The **+** button on the composer offers **Attach file**, **Image**, and **Check origin**. The model chip below the text box switches between **Cortex 1 Mini** and **Cortex Teutonic-1**, sets the **Thinking** level, and turns on **Deep Research**. + <Step title="Look around the shell"> + The sidebar holds **New chat**, a **WORKSPACE** section (**Planning**, **Projects**, **Library**, **Plugins**, **Artifacts**, **Customize**), a **PINNED** section and **RECENTS**. **Switch product** at the top moves between Chat, Code and Bot without reloading anything. In Chat, `Ctrl` with `K` (`⌘` `K` on a Mac) opens **Search**, and `Ctrl` with `/` opens the full **Keyboard shortcuts** sheet. + + A **Two-minute orientation** card offers **Start tour**, which walks you through the product menu, the command menu and Settings. **Dismiss onboarding** hides it for good. </Step> - <Step title="Sign in when you want more"> - 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). + <Step title="Sign in to keep your work"> + Choose **Sign in to save your work** in the sidebar footer, or **Sign in** on any public page. The dialog runs on `cortex.foundation` and says so. Signing in does not navigate away: the conversation on screen is kept, the sidebar swaps the **Guest** row for your account, and the dialog closes on its own about a second after it reads **You're signed in.** + + The available methods, and what to do when a sign-in banner reports a problem, are on [Accounts and sign-in](/getting-started/accounts). </Step> - <Step title="Pick your next surface"> - | 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) | + <Step title="Open a second application"> + Use **Switch product** in the sidebar to pick **Cortex Code** or **Cortex Bot**. If you are still a guest, a dialog headed **This space is reserved** offers **Sign in** or **Continue in Chat**. If you are signed in but not yet invited, a closed-beta dialog offers **Continue in Chat** only. Neither dialog can be dismissed and neither redirects, so the address bar keeps the URL you asked for. </Step> </Steps> +<Note> +Guest conversations live in the browser session. Sign in before you close the tab if you want to keep the one you just started. Guests also have no projects, no Library, no memory and no uploads, because a guest session could never come back to revoke something it created. +</Note> + +## Set the model and the thinking level + +Chat picks a default model for new chats and lets you switch at any time from the composer. The current public models are **Cortex 1 Mini**, **Cortex Teutonic-1** and, for pictures, **Cortex-Image-1**. All three are previews. + +To change the default rather than the current chat, open **Settings** from the sidebar footer and stay on **Models**. **Default model** applies to new chats, and **Default thinking level** (**Low**, **Medium**, **High**) sets how much time Cortex spends reasoning before it answers. Every published model is available from the Free plan up, so the picker will not lock a row on you. See [Models](/reference/models). + ## Install the desktop app or the CLI -The browser runs Chat, Code Cloud, and Bot Cloud. **This PC** and **SSH** hosts exist only on the desktop app and the CLI — that is where the code runs, not a missing feature in the browser. +The browser covers Chat, and the cloud runtimes behind Code and Bot. A local host, meaning your own machine or a server you own, exists only on the desktop app and the command line. That is a deliberate split, not a missing browser feature. + +<Tip> +The desktop app also adds a few things the web cannot offer at all: a floating companion with a global **Quick Chat**, and **Appshots**, a capture chord for the last Chat or Code thread you used. The web has no global hotkey. +</Tip> -<p className="ink-cta-row"> - <a className="ink-btn" href="/getting-started/downloads">Download Cortex</a> - <a className="ink-btn ink-btn-quiet" href="/cli/install">Install the CLI</a> -</p> +Start from [Ways to run Cortex](/getting-started/downloads) for the desktop app, or [Install the CLI](/cli/install) for the terminal. ## Then pick a surface <CardGroup cols={2}> - <Card title="Chat guides" img="/images/banners/chat.png" href="/chat"> - Projects, Library, plans, models, tools, research, and images. + <Card title="Chat quickstart" icon="comments" href="/chat/quickstart"> + Create a project with standing instructions, add files to Library, and run a research task. + </Card> + <Card title="Code quickstart" icon="code" href="/code/quickstart"> + Connect a repository and start your first session with approvals turned on. </Card> - <Card title="Code guides" img="/images/banners/code.png" href="/code"> - Sessions in an isolated Cloud guest, GitHub, Ask / Plan / Agent, pull-request review. + <Card title="Bot quickstart" icon="robot" href="/bot/quickstart"> + Create a bot, open its computer, and watch it work while it asks before consequential steps. </Card> - <Card title="Bot guides" img="/images/banners/bot.png" href="/bot"> - Always-on agents with their own computer, approvals, routines, and skills. + <Card title="CLI quickstart" icon="terminal" href="/cli/quickstart"> + Sign in from the terminal and run a session in a checkout you already have. </Card> - <Card title="Design guides" img="/images/banners/design.png" href="/design"> - Persistable canvases hosted from Chat or Code, edited in the Design desktop app. + <Card title="Design quickstart" icon="pen-ruler" href="/design/quickstart"> + Install the Cortex Design desktop app and make your first canvas. + </Card> + <Card title="Security quickstart" icon="shield-halved" href="/security/quickstart"> + Put review on a repository and read the check run it writes on a pull request. </Card> </CardGroup> @@ -80,24 +95,27 @@ The browser runs Chat, Code Cloud, and Bot Cloud. **This PC** and **SSH** hosts <AccordionGroup> <Accordion title="Do I need an account to try Cortex?"> - No. Chat works as a guest with a daily and monthly message allowance (100 messages today and 500 this month at the time of writing — the banner above the composer shows the live numbers). Everything that must survive a closed tab — projects, files, memory, Code, Bot — needs a signed-in account. + No. Chat works as a guest with 100 messages a day and 500 over thirty days. The banner above the composer shows how many are left. Signing in moves you to the Free plan, whose windows start fresh on the account: an unused guest allowance does not carry over. + </Accordion> + <Accordion title="Why does Cortex Code say the space is reserved?"> + You are not signed in. Code and Bot are member surfaces. Choose **Sign in**, or **Continue in Chat**. </Accordion> - <Accordion title="Where does my code run?"> - Web Code runs in an isolated Cloud guest. Chat's Python tool is a small snippet sandbox with no workspace. Bot's computer is a Cloud guest with a desktop. **This PC** and **SSH** are desktop and CLI hosts. See [Security](/security/overview). + <Accordion title="I am signed in and Cortex Code still will not open."> + Code and Bot are in closed beta, so a signed-in account also has to be invited. The dialog offers **Continue in Chat** only. Ask for an invitation, and use Chat in the meantime. </Accordion> - <Accordion title="Why does /code show “This space is reserved”?"> - You are not signed in. Code and Bot are member surfaces so that a guest session can never create something it cannot come back to revoke. Choose **Sign in**, or **Continue in Chat**. + <Accordion title="Can I change plan from inside the app?"> + **Settings** then **Plan & billing** lists the plans and marks the one you are on, but checkout is not available yet on this deployment: expect a hold badge on the action rather than a payment form. [Plans and quotas](/getting-started/plans) explains what each plan includes. </Accordion> <Accordion title="Is there a public inference API?"> - Not on this site. The inference Platform API is [coming soon](/platform) and has no endpoints to document yet. The [API tab](/api/overview) covers the problem-document format the app already uses. + Not yet. There is no public model-inference API, no endpoints and no programmatic keys to document. See [Platform API](/reference/platform-api). </Accordion> </AccordionGroup> -## Next +## Related -1. [Chat quickstart](/chat/quickstart) — projects, files, models, and research. -2. [Code quickstart](/code/quickstart) — a Cloud session on one of your repositories. -3. [Bot quickstart](/bot/quickstart) — a bot with its own computer. -4. [CLI quickstart](/cli/quickstart) — the same Code sessions from a terminal. -5. [Accounts](/getting-started/accounts) — what signing in unlocks, and what it does not. -6. [Troubleshooting](/getting-started/troubleshooting) — when a message is not an error. +- [What is Cortex](/getting-started/what-is-cortex) +- [Which product do I need?](/getting-started/choose-a-product) +- [Accounts and sign-in](/getting-started/accounts) +- [Plans and quotas](/getting-started/plans) +- [Keyboard shortcuts](/getting-started/keyboard-shortcuts) +- [Troubleshooting](/getting-started/troubleshooting) diff --git a/getting-started/report-a-bug.mdx b/getting-started/report-a-bug.mdx new file mode 100644 index 0000000..428c36d --- /dev/null +++ b/getting-started/report-a-bug.mdx @@ -0,0 +1,135 @@ +--- +title: "Report a bug" +description: "File a bug from inside Cortex: where the dialog lives, what to write, screenshot limits, what is sent, and where other reports go." +icon: "bug" +keywords: ["bug report", "feedback", "send report"] +--- + +Cortex takes bug reports in the product. A signed-in account opens a dialog, writes what happened, +attaches a screenshot or two, and sends it. The report stays inside Cortex; nothing is copied to a +public issue tracker, and there is no form to fill in somewhere else. + +This page covers what to check before you file, the three places the dialog opens from, what to +write in each field, the screenshot rules, what Cortex sends along with your words, and where a +documentation problem or a security finding goes instead. + +<Note> +Reporting a bug needs an account. A guest has no **Report a bug** control and the request is +refused, so sign in first. +</Note> + +## Before you file + +Two minutes of checking often saves the round trip. + +<Steps> + <Step title="Check whether Cortex is down"> + If everything is failing at once rather than one action, look at + [System status](/reference/status) or [status.cortex.foundation](https://status.cortex.foundation) + before writing anything. A maintenance window shows its own screen, titled **Cortex is taking a + short break**, with a **Time remaining** countdown. + </Step> + <Step title="Read the message you were given"> + Most failures carry a short heading and a stable code. **Not included in your plan**, **You have + used this plan limit** and **Please sign in again** are expected answers, not bugs. + [Troubleshooting](/getting-started/troubleshooting) lists what each message means, and the + [problem catalog](/problems) has a page per code. + </Step> + <Step title="Copy the reference id"> + When a failure was on Cortex's side, the card shows a reference id and asks you to quote it. + Paste it into your report; it is the fastest way for the team to find your request. + </Step> +</Steps> + +## Open the dialog + +There are three entry points, and they all open the same **Report a bug** dialog: + +| Where | How to get there | +| --- | --- | +| Sidebar footer | The **Report a bug** control beside **Settings** | +| Settings | **Settings** and then **General**, at the **Report a bug** row | +| The **Beta Pro offer** banner | A **Report a bug** button on the banner, while that banner is on screen | + +The first two are permanent. The banner is dismissible, and dismissing it does not take the other +two away. + +## Fill in the report + +The dialog opens with a single line of intent, "Tell us what went wrong. We read every report", +and three fields. + +<Steps> + <Step title="Title"> + A short summary, up to 200 characters. One sentence naming the thing that broke beats a + paragraph. + </Step> + <Step title="What happened"> + Up to 8,000 characters for the steps you took, what you expected, and what you saw instead. The + field's own prompt asks for exactly those three. Add the reference id here if you have one. + </Step> + <Step title="Where it happened"> + Pick a surface: **Not sure**, **Cortex Chat**, **Cortex Code** or **Cortex Bot**. **Not sure** + is a real answer, so use it rather than guessing. + </Step> + <Step title="Send report"> + Choose **Send report**. On success the dialog shows **Report sent** with "Thank you. We will + look at this", and a **Done** button. **Cancel** closes without sending. + </Step> +</Steps> + +## Screenshots + +Screenshots are optional and usually worth adding. You can drop files onto the dialog, paste them +from the clipboard, or use **Add screenshots**. Each thumbnail has a remove control if you change +your mind. + +| Rule | Value | +| --- | --- | +| Formats | PNG, JPEG or WebP | +| Count | Up to five per report | +| Size | 4 MB each | + +A file in another format is refused with "Screenshots must be PNG, JPEG or WebP", and an oversized +one with "Each screenshot can be at most 4 MB". Shrink or re-save the image and try again. + +## What is sent + +Your report carries the title, the description, the surface you picked if you picked one, your +screenshots, and the page you were on, which Cortex attaches for you. That is all. Reports stay +inside Cortex and reach the team, the title and description are encrypted at rest, and nothing is +forwarded to a public tracker. + +Cortex does not publish a mailbox for bug reports. The dialog is the channel, which is also why a +guest cannot file one: a report needs an account to come back to. + +## When a report will not send + +| What you see | Meaning | Do this | +| --- | --- | --- | +| No **Report a bug** control at all | You are browsing as a guest | Sign in, then try again | +| **Please sign in again** | The session expired while the dialog was open | Sign in again; you return to where you were | +| **Too many requests** | You are over the hourly ceiling of five reports or fifteen screenshot uploads | Wait for the window to clear, then send the rest. See [rate_limited](/problems/rate_limited) | +| "Screenshots must be PNG, JPEG or WebP." | One attachment is not an accepted image | Convert or drop that file | +| "Each screenshot can be at most 4 MB." | One attachment is too large | Re-save it smaller | + +## Reports that belong somewhere else + +<CardGroup cols={2}> + <Card title="A mistake on this site" icon="book-open" href="https://github.com/CortexLM/docs"> + Documentation lives in its own public repository. A page that is wrong, stale or missing belongs + there rather than in the product dialog. + </Card> + <Card title="A security weakness" icon="shield" href="/bounty/report"> + A suspected vulnerability is not a bug report. Cortex Bounty has its own intake and its own + scoring. + </Card> +</CardGroup> + +## Related + +- [Troubleshooting](/getting-started/troubleshooting) for what a message in the product means. +- [Problem catalog](/problems) for the code on a failure card. +- [System status](/reference/status) for outages and maintenance windows. +- [Frequently asked questions](/getting-started/faq) for the short answers. +- [File a report](/bounty/report) for security findings. diff --git a/getting-started/settings.mdx b/getting-started/settings.mdx index 00ec2e8..3df69a2 100644 --- a/getting-started/settings.mdx +++ b/getting-started/settings.mdx @@ -1,91 +1,131 @@ --- title: "Settings" -description: "Theme, language, answer font, keyboard shortcuts, default models, integrations, privacy, and billing — everything under Settings in the web app." -keywords: ["preferences", "theme", "language", "shortcuts", "privacy"] +description: "Settings opens as an overlay over Chat, Code or Bot. Seven tabs in two groups, plus a search that looks across all of them." +icon: "gear" --- -Open **Settings** from the sidebar footer, or go to `cortex.foundation/settings`. It is a panel with two sections: **Preferences** (General, Models, Integrations, Code) and **Account** (Data & privacy, Plan & billing). Guests can browse it; account controls unlock after you sign in. +Settings in Cortex is an overlay dialog, not a page. It opens over whatever you were doing in Cortex Chat, Cortex Code or Cortex Bot, and closing it puts you back exactly where you were. Guests can browse it: the account controls say they need an account rather than disappearing. -<Frame caption="Settings → General: account, theme, language, answer font, and keyboard shortcuts."> - <img src="/images/product/settings-general.png" alt="Settings panel — General tab with Account, Theme, Language, Answer font, and Keyboard shortcuts" /> -</Frame> +This page names every tab and the controls inside it, so you can find a setting you cannot place. Depth on a specific area lives on that area's page, and this page links out where that is true. -## General +## Open Settings + +Choose **Settings** in the sidebar footer. Two deep links open the overlay directly: `cortex.foundation/settings` opens it over Chat, and `cortex.foundation/code/settings` opens it over Code. Adding `?tab=` and a tab slug opens a named tab, and an unknown value falls back to **General**. The slugs are `general`, `models`, `integrations`, `code`, `approvals`, `data-privacy` and `plan-billing`. + +Two behaviours are worth knowing. Moving to another page in the product closes Settings, so it never traps you. And dismissing the overlay rewrites the address back to the product, so the Back button never returns you to a blank Settings URL. -| Setting | Options | Notes | +## The seven tabs + +The left rail has two groups: `PREFERENCES` and `ACCOUNT`. + +| Group | Tab | What is inside | | --- | --- | --- | -| **Account** | Sign in / manage account | Shows “You're browsing as a guest” until you sign in | -| **Theme** | Light · Dark · System | How Cortex looks on this device | -| **Language** | English, Français, Español, Deutsch, 日本語, 简体中文, Português (Brasil), 한국어 | Interface language only. Model prompts stay in English. | -| **Answer font** | Sans · Serif | Serif is easier on the eyes for long answers. Marked *coming soon* at the time of writing. | +| `PREFERENCES` | **General** | Your email and display name, theme, interface language, keyboard shortcuts, custom instructions, desktop extras, reporting a bug | +| `PREFERENCES` | **Models** | Default model, default thinking level, reasoning summaries, voice and token allowances | +| `PREFERENCES` | **Integrations** | Connected apps, MCP servers, roles, directory provisioning | +| `PREFERENCES` | **Code** | Cortex Code's default model, fallbacks, allowlist, providers, pull-request review, hooks | +| `PREFERENCES` | **Approvals** | The approval matrix across Chat, Code and Bot, spend budget and receipts | +| `ACCOUNT` | **Data & privacy** | History, memory, cookies, activity, two-factor, compliance, export and deletion | +| `ACCOUNT` | **Plan & billing** | Your plan, quota meters, storage, usage ledger, plan changes | + +<Note> +There is no Plugins tab and no Compliance tab. Plugins live in the sidebar under `WORKSPACE`, and compliance is a section inside **Data & privacy**. If you have read otherwise, that list was stale. +</Note> -### Keyboard shortcuts +## Search inside Settings -Shortcuts are listed at the bottom of **General**. On Windows and Linux, read ⌘ as **Ctrl**. +The field at the top of the left rail is **Search settings**, and it searches rows across every tab rather than only the open one. Picking a result jumps to that row on its tab. The count reads as `{count} results`, `Clear search` returns to browsing, and no match shows `No settings match "{query}"` with `Try a shorter word, or clear the search to browse all tabs.` -| Action | Shortcut | +Most rows save themselves: the control shows `Saving…` and then `Saved`. Two badges tell you when a row is not usable. `COMING SOON` means the control is designed and drawn but not built yet. `HOLD` means the action cannot be completed on this deployment right now. + +## General + +| Row | What it does | | --- | --- | -| New chat | ⌘ K | -| Toggle sidebar | ⌘ \ | -| Focus composer | ⇧ Esc | -| Copy last answer | ⌘ ⇧ C | -| Stop response | Esc | -| Send | Enter | -| New line in the composer | Shift + Enter | - -<Frame caption="The shortcut list under Settings → General."> - <img src="/images/product/settings-shortcuts.png" alt="Keyboard shortcuts — New chat, Toggle sidebar, Focus composer, Copy last answer, Stop response" /> -</Frame> +| **Email** | `The address you sign in with.` Read-only, and members only. | +| **Display name** | `How Cortex refers to you.` Up to 120 characters. | +| **Report a bug** | `Send a title, a description and optional screenshots. This stays in Cortex.` Signed-in accounts only. | +| **Theme** | `Light`, `Dark` or `System`. `System` follows the operating system as it changes. | +| **Language** | `Interface language. Model prompts stay in English.` Eight entries. | +| **Answer font** | `Sans` or `Serif`. Disabled, marked `COMING SOON`. | +| **Desktop companion** | A preview of the desktop app's floating companion, global **Quick Chat** and activity tray. | +| **Keyboard shortcuts** | A two-row list plus a button that opens the full sheet. | +| **Scheduled tasks** | `Review and manage Chat schedules.` An `Open` link to the Scheduled page. | +| **Custom instructions** | `How Cortex should reply` and `What Cortex should know about you`, with the tone chips `Concise`, `Direct` and `Teacher`. Guests cannot set them, and some deployments answer `Custom instructions are not available on this deployment.` | +| **Appshots** | The desktop-only capture chord: `⌘ ⌘` on a Mac, `Alt Alt` on Windows. `This chord lives on the desktop app. The web has no global hotkey.` | + +A guest sees `You're browsing as a guest.` and `Sign in to manage your account` in place of the email and display-name rows. ## Models -**Models** lists what Chat can serve and lets you choose defaults for new chats. You can always switch per conversation from the composer chip; see [Models](/chat/models). - -| Setting | What it does | +| Row | What it does | | --- | --- | -| **Default model** | Used for new chats. Cortex 1 Mini (default), Cortex Teutonic-1, Cortex-Image-1 for pictures. *Coming soon* as a saved default. | -| **Default thinking level** | Low · Medium · High — how much time Cortex spends reasoning before it answers. *Coming soon* as a saved default. | -| **Show reasoning summaries** | Display a short summary of the model's thinking above each answer. *Coming soon.* | +| **Default model** | `Used for new chats. You can switch models anytime from the composer.` | +| **Default thinking level** | `Low`, `Medium` or `High`. `How much time Cortex spends reasoning before it answers.` | +| **Show reasoning summaries** | `Display a short summary of the model's thinking above each answer.` | +| **Voice minutes** | `Spoken live-voice time on this plan, separate from model tokens.` | +| **Model tokens** | `Text and reasoning tokens. Not combined with voice minutes.` | +| **Background conversations** | `Keep a live voice session going when you leave the tab. Off by default.` | +| **Live on lock screen** | `Show the last spoken line on a lock card. Requires Background conversations.` | -Model availability depends on your plan. During peak hours new chats may fall back to a faster model. +The tab carries its own notice: `Model availability depends on your plan. During peak hours new chats may fall back to a faster model.` Where a plan or a deployment does not offer something, the row says so, for example `Voice minutes are not available on this plan.` or `No voice-capable models on this plan.` See [Models](/chat/models) and [Voice](/chat/voice). ## Integrations -**Integrations** is where a signed-in account connects apps and MCP servers. GitHub is live with four tools (list pull requests, list issues, create issue, and more); Linear, Slack, Notion, and Vercel are listed as coming soon. Under **MCP servers** you attach a Model Context Protocol server over HTTP by name and URL, with an optional bearer token. Details: [Tools and connectors](/chat/tools). +**Apps** connects an app so you can act on it from chat: `A connected integration adds its tools to your conversations.` Rows show `Connected`, `Coming soon`, `Add`, `Disconnect` and a tool count. **MCP servers** attaches a Model Context Protocol server over HTTP by name and URL, with an optional bearer token; a server that advertised nothing shows `No tools were advertised when this server was attached.` A **Cortex Bot** row controls whether your mascots may use those tools, off by default, and `each call still asks first`. See [Tools and connectors](/chat/tools) and [MCP servers](/chat/mcp-servers). + +The rest of the tab describes an organisation rather than something you can create. **Roles** reports `Manage connectors`, `Manage roles` and `Manage billing` as `Granted` or `Not granted`, and a deployment that reports no role says `This deployment does not report roles, so nothing here is inferred.` **Organization** lists servers an organisation provisioned, and most deployments answer `No organization servers on this deployment.` **Directory Sync** is plan-gated and usually reports `Directory Sync is not available on this account yet.`, with the stance `Your identity provider stays the source of truth for who exists and who may sign in. Cortex never acts as your identity vendor.` + +There are no teams and no invitations in Cortex today, so treat these rows as reserved rather than as a workspace you can staff. ## Code -**Settings → Code** holds Code's default model, fallbacks, and an allowlist of model references. The list of enabled providers is shown read-only; keys are sealed in the keyring, never shown, never in git. Most people leave this section alone — Code picks a sensible default. See [Code sessions](/code/sessions). +This tab configures Cortex Code. Most people leave it alone. + +| Row | What it does | +| --- | --- | +| **Default model** | `A provider/model reference from the catalogue. Fallbacks take over in order when the main provider fails.` | +| **Fallbacks** | `Tried in order after the default model.` | +| **Allowlist** | `Empty: any model from an enabled provider is allowed. Otherwise only these provider/model references are.` | +| **Providers** | The hosted catalogue, refreshed for you. Provider keys are never shown in the app. Chips read `Connected`, `Key required` or `Disabled`. | +| `Pull request review` | **Auto-review when a pull request opens** and **Mention @cortex on a pull request**. Both are off, and each says that Code reviews of that kind are not available yet. | +| **Lifecycle hooks** | `Match a tool and a pattern. Timeout or an unreachable store is deny.` Often `Hooks are not configured on this deployment.` | +| **Windows daemon** | A shared Code daemon on a Windows machine, where the deployment offers one. | +| **Show diffs on bash results** | Draws a unified diff in the worklog as hunks. | +| **Platform** | Managed agent sessions, prompt-cache diagnostics and gateway pricing. Usually held: `These controls remain unavailable until the deployment publishes their API capabilities.` | + +See [Code settings](/code/settings) for the depth, and [Cortex Security](/code/security) for the review policy, which lives inside Code rather than here. + +## Approvals + +**Approval matrix** is the centre of this tab: `Choose Ask or Always ask for each verb on Chat, Code, and Bot.` Columns are `Chat`, `Code` and `Bot`; rows are `Read`, `Edit`, `Shell` and `Pay`. `Pay stays Always ask.` and `Bot cannot publish. That cell is absent, not disabled.` Autonomy can be earned after a threshold of approvals, with a decay measured in days. + +The tab also holds **Export policy** (`Download the current matrix as JSON.`), **Standing spend budget** (`A monthly cap for metered spend. Empty means no standing budget.`) and **Spend receipts**, which starts at `No spend receipts yet.` When Cortex asks in the moment, your choices are `Allow once`, `Allow up to a budget` or `Deny`. See [Approvals in Code](/code/approvals) and [Approvals in Bot](/bot/approvals). ## Data & privacy -| Control | Default | 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. | +The account tab, in render order: **Save chat history** and **Improve the model** (both disabled and marked `COMING SOON`), **Activity**, **Computer history**, **Cookies**, the memory rows (**Use memory**, **Include sensitive topics**, **How long to keep memories**, **Memory**), **Account security**, **Two-factor authentication**, **Trusted contact**, **Crisis notify**, **Age assurance (13+)**, **API keys**, **Compliance** (`What this deployment certifies — and what it does not.`) and **Your data** (`Export everything we hold, or delete it permanently. Deletion takes effect within 30 days.`). -See [Security](/security/overview) for what Cortex stores and where code runs. +It closes with a `WHAT WE STORE` card. See [Data and privacy](/getting-started/data-and-privacy) for the full walkthrough and [Two-factor authentication](/getting-started/two-factor) for the confirmation that guards export and deletion. ## Plan & billing -Your current plan, today's and this month's usage with reset timers, the plan ladder (Free, Go, Plus, Pro), and billing history. See [Plans and quotas](/getting-started/plans). +Your current plan and price, the quota meters, a `STORAGE` meter for Library, the usage ledger split by product, `Change plan`, and `Billing history`. See [Plans and quotas](/getting-started/plans). -## Settings elsewhere +## Settings that live elsewhere -| Surface | Where settings live | +| Surface | Where its settings live | | --- | --- | -| **CLI** | `/settings` in the TUI, `cortex config`, and `~/.cortex/config.toml`. See [CLI configuration](/cli/configuration). | -| **Connected apps** | **Customize → Connectors** in the sidebar, and **Settings → Integrations**. See [Tools and connectors](/chat/tools). | -| **Cortex Security policy** | `/code/security/policy` in the app. See [Cortex Security](/code/security). | - -## Next - -- [Accounts](/getting-started/accounts) — what signing in unlocks. -- [Plans and quotas](/getting-started/plans) — the usage panel under Plan & billing. -- [Security and privacy](/security/overview) — cookies, storage, and deletion. -- [Chat troubleshooting](/chat/troubleshooting) — when a setting does not seem to take. +| Cortex CLI | `/settings` in the terminal interface, `cortex config`, and the CLI config file in your home directory. See [CLI configuration](/cli/configuration). | +| Connected apps | **Customize** in the sidebar, and **Settings → Integrations**. See [Tools and connectors](/chat/tools). | +| Cortex Security policy | The review policy page inside Cortex Code. See [Review policy](/security/review-policy). | +| Cortex Design | Its own settings inside the canvas app. See [Design settings](/design/settings). | + +## Related + +- [Accounts and sign-in](/getting-started/accounts) - what the account rows in General reflect. +- [Plans and quotas](/getting-started/plans) - the meters on the Plan & billing tab. +- [Data and privacy](/getting-started/data-and-privacy) - every section of the Data & privacy tab. +- [Interface language](/getting-started/language) - the eight languages and what stays English. +- [Keyboard shortcuts](/getting-started/keyboard-shortcuts) - the full sheet behind the General row. +- [Notifications](/getting-started/notifications) - the bell, which sits outside Settings. diff --git a/getting-started/troubleshooting.mdx b/getting-started/troubleshooting.mdx index e8c3789..b076875 100644 --- a/getting-started/troubleshooting.mdx +++ b/getting-started/troubleshooting.mdx @@ -1,89 +1,123 @@ --- title: "Troubleshooting" -description: "What the web app shows when something is off, what it means, and what to do — gates, quotas, reconnects, and product-facing errors." -keywords: ["errors", "problems", "fixes", "not working", "support"] +description: "The messages Cortex shows when something will not run, what each one means, and what to do, grouped by what you were trying to do" +icon: "life-ring" --- -Cortex prefers a clear message over a spinner. When something cannot run, the product says so in plain words and, where it can, tells you what to do next. This page collects those messages across Chat, Code, and Bot. The CLI has [its own page](/cli/troubleshooting). +Cortex prefers a clear message over a spinner. When something cannot run, the product says so in plain words and, where it can, tells you what to do next. Quotas and permission checks fail closed: you get told the window is used up, rather than a quietly worse answer. -## Sign-in and access +This page collects those messages across Cortex Chat, Cortex Code and Cortex Bot, grouped by what you were trying to do when you met one. Every failure that came from the server also carries a stable problem code with its own page, linked where it applies. -| What you see | Meaning | Do this | +## Signing in + +| What you see | What it means | What to do | | --- | --- | --- | -| **This space is reserved** on `/code` or `/bot` | You are a guest. Code and Bot are member surfaces. | **Sign in**, or **Continue in Chat**. | -| **Sign in to continue** in the composer banner | Today's or this month's guest allowance is used up. | Sign in to continue on Free, or wait for the reset shown under **Settings → Plan & billing**. | -| A dialog asking for an authenticator code | You asked to export or delete data. | Confirm with your authenticator app. | -| No **Connect** control for an app or for GitHub | That connection is not available on this deployment, or you are a guest. | Sign in; if the control is still missing, it is not offered here. | +| `The server could not be reached. Try again.` | The sign-in request did not land | Choose **Retry**. It only ever re-fires on a click, because retrying sends another email | +| `That sign-in was not completed. Choose another option.` | The sign-in step was cancelled before it finished | Start again, or pick a different method | +| `The sign-in window could not be opened. Allow pop-ups and try again.` | Your browser blocked the sign-in window | Allow pop-ups for `cortex.foundation`, then retry | +| `This address does not look valid. Check the domain after the @.` | The email address was rejected before anything was sent | Fix the address | +| `Enter a work email or company domain.` | Single sign-on needs a work address, not a personal one | Use your organization's address | +| `{email} does not have access to this Cortex space (403).` | The account exists but is not in this space | `Ask your administrator for an invitation, or try another account.` | +| `This sign-in attempt has expired. Start again.` | The emailed code or the attempt behind it timed out | Start the sign-in again from the dialog | +| `Please sign in again` | Your session expired while you were working | Sign in. You return to where you were. See [`unauthenticated`](/problems/unauthenticated) | + +There is no second-factor field in the sign-in dialog. If your organization requires a second factor it runs during the identity step, not here. Two-factor inside Cortex is only used to confirm sensitive actions, described under [Two-factor authentication](/getting-started/two-factor). -## Quotas and plans +## Opening Cortex Code or Cortex Bot -| What you see | Meaning | Do this | +Both are member surfaces, and you meet one of two dialogs. Neither redirects: the address bar keeps the URL, and neither can be dismissed with Escape or by clicking outside. + +| What you see | What it means | What to do | | --- | --- | --- | -| [`quota_exceeded`](/problems/quota_exceeded) | The daily or monthly window is used up. | Wait for the reset, or move to a plan with higher ceilings. | -| [`entitlement_required`](/problems/entitlement_required) | The plan does not include that capability. | Compare plans under **Settings → Plan & billing**. | -| [`rate_limited`](/problems/rate_limited) | Too many requests in a burst. | Pause, then retry. | -| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Too many things running at once on the account. | Let a session or run finish first. | +| `This space is reserved` | You are a guest. The body reads that the product `is a reserved space for signed-in accounts. Chat stays available without an account.` | Choose **Sign in**, or **Continue in Chat** | +| `{product} is in closed beta` | You are signed in but not invited: `{product} is available to invited accounts. Chat stays open for everyone.` | Only **Continue in Chat** is offered. Ask for an invitation | +| `You do not have access to this` | A permission check refused the action | `If you expected to, whoever administers the workspace can grant it.` See [`forbidden`](/problems/forbidden) | +| No **Connect** control for an app or for GitHub | Not offered on this deployment, or you are a guest | Sign in. If it is still missing, it is not offered here | -See [Plans and quotas](/getting-started/plans). +Cortex Chat is never gated. See [Accounts and sign-in](/getting-started/accounts) for what a guest can and cannot do. -## Chat +## Running out of what your plan allows -| What you see | Meaning | Do this | +| What you see | What it means | What to do | | --- | --- | --- | -| **Cortex is responding…** with a spinner on the send button | A turn is in flight. | Wait, or press **Esc** to stop it. | -| An error square where an image should be | The Library fetch or the generation failed. It is never a spinner. | Retry the request. | -| **Improving prompt…** on an image card | The picture is queued; Chat is turning your ask into a complete scene first. | Wait — the card becomes a skeleton, then the image. | -| No mic in the composer, no **Listen** under an answer | Voice is not available on this deployment. | Nothing to configure — the capability is off, not broken. | -| Origin check says it cannot run | The check is unavailable here. Cortex says so rather than guessing. | Ask again later; do not treat silence as a verdict. | -| A reply cut short, then the thread reconnects | The connection dropped. Run state lives in the thread. | Do not resend; the reply that started continues. | -| **Deep Research** is missing | Deep Research is a Chat feature. | You are in Code or Bot; switch to Chat. | +| `Plan limit reached` / `You have used everything this plan allows in the current window.` | A quota window is spent | Wait for the reset shown as `Resets in {label}`, or choose **Upgrade for unlimited**. A `Continue with {model}` action may also be offered | +| `You have used this plan limit` | The same thing, from the generic error card | `The limit resets on its own. Upgrading lifts it immediately.` See [`quota_exceeded`](/problems/quota_exceeded) | +| `{left} of {limit} free messages left` above the composer | You are a guest and the allowance is counting down | Sign in before it runs out to keep going | +| `Sign in to continue` in the composer banner | The guest allowance is used up | Sign in. The Free plan's windows start fresh on the account | +| `Not included in your plan` | The plan does not include that capability | Compare plans under **Settings → Plan & billing**. See [`entitlement_required`](/problems/entitlement_required) | +| `Too many requests` | Requests arrived faster than the limit allows | `This clears by itself.` Pause, then retry. See [`rate_limited`](/problems/rate_limited) | +| `Too much running at once` | Too many runs in parallel on the account | `One finishing frees a slot.` See [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | +| `That is too large to send` | The attachment is over the limit | `Files can be at most 10 MB. Remove or shrink the attachment and try again.` See [`payload_too_large`](/problems/payload_too_large) | +| `That file type is not supported` | The format is not accepted | `Attach a different format, or paste the contents into the message instead.` | + +The two windows the product actually enforces are messages today and messages this month. A turn charges both, and whichever runs out first is the one that stops you. See [Plans and quotas](/getting-started/plans). -## Code +## Getting an answer in Chat -| What you see | Meaning | Do this | +| What you see | What it means | What to do | | --- | --- | --- | -| **Reconnect** next to GitHub | The GitHub connection lapsed. | Choose **Reconnect** in Code Home or **Settings → Integrations**. | -| Code says Cloud compute is unavailable | The deployment has no Cloud runtime right now. Code never runs your repository on the API instead. | Try again later, or use **This PC** on the desktop app or CLI. | -| `/code/secrets` sends you home | There is no Secrets page. Environment for a guest belongs to that guest. | Set environment inside the session. | -| A review shows **failed**, not approved | A Cortex Security review that could not run is stored as failed. | Read the check run; fix and push. | +| A spinner on the send button | A turn is in flight | Wait, or press `Esc` to stop it | +| A reply cut short, then the thread reconnects | The connection dropped. Run state lives in the thread | Do not resend. The reply that started continues | +| An error square where an image should be | The fetch or the generation failed. It is never a spinner | Retry the request | +| `Improving prompt…` on an image card | The picture is queued while Chat completes the scene | Wait. The card becomes a skeleton, then the image | +| No mic in the composer and no **Listen** under an answer | Voice is not available on this deployment | Nothing to configure. The capability is off, not broken | +| Origin check says it cannot run | The check is unavailable here | Ask again later. Silence is not a verdict | +| **Deep Research** is missing | It is a Chat feature | You are in Code or Bot. Switch to Chat | +| `This request was declined` | The request falls outside what Cortex will help with | `Rewording it may be enough.` Retrying the same words will not. See [`content_policy`](/problems/content_policy) | +| `Support is available` | The conversation was paused so you could see support resources | Read the resources shown. See [`safety_intervention`](/problems/safety_intervention) | -More: [Code troubleshooting](/code/troubleshooting). +More in [Chat troubleshooting](/chat/troubleshooting). -## Bot +## Running a session in Cortex Code -| What you see | Meaning | Do this | +| What you see | What it means | What to do | | --- | --- | --- | -| **Connecting** on the Computer rail | The Cloud guest is starting. | Wait a moment. | -| **Stream Unavailable** | The guest is running but its live desktop is not reachable. | Use **Open desktop** again, or **Sleep** and wake it. | -| An **Allow / Deny / Always** widget | The bot parked a consequential step for you. Nothing runs until you choose. | Read the step, then decide. | -| The setup form instead of a bot list | The account has no bots yet. That is a setup, not an empty list. | Create a bot. | +| **Reconnect** next to GitHub | The GitHub connection lapsed | Reconnect from Code Home or **Settings → Integrations** | +| Cloud compute is unavailable | The deployment has no Cloud runtime right now | Try again later, or use a local host from the desktop app or the Cortex CLI | +| A Secrets URL sends you home | There is no Secrets page | Set environment inside the session | +| A review shows `failed` rather than approved | A review that could not run is stored as failed | Read the check run, then fix and push | -More: [Bot troubleshooting](/bot/troubleshooting). +More in [Code troubleshooting](/code/troubleshooting) and [CLI troubleshooting](/cli/troubleshooting). -## Service errors +## Driving a bot's computer -Every API failure is a problem document with a stable `code`, and the web app renders catalogue copy for it. Three codes may show a secondary `detail` line: `validation_failed`, `bad_request`, `invalid_state`. User-facing text names a product surface, never a vendor. Full list: [Problem catalog](/problems). +| What you see | What it means | What to do | +| --- | --- | --- | +| `Connecting` on the Computer rail | The computer is starting | Wait a moment | +| `Stream Unavailable` | The computer is running but its live desktop is not reachable | Open the desktop again, or sleep and wake it | +| An **Allow** / **Deny** / **Always** widget | The bot parked a consequential step. Nothing runs until you choose | Read the step, then decide | +| `computer could not start` in your notifications | A bot's computer failed to wake | Open the bot and try the computer again | +| The setup form instead of a bot list | The account has no bots yet. That is a setup, not an empty list | Create a bot | + +More in [Bot troubleshooting](/bot/troubleshooting). -| Code | Retry? | -| --- | --- | -| [`service_unavailable`](/problems/service_unavailable) | Yes, after a pause | -| [`upstream_failure`](/problems/upstream_failure), [`upstream_timeout`](/problems/upstream_timeout) | Yes | -| [`no_capacity`](/problems/no_capacity) | Yes; higher plans get priority when the fleet is busy | -| [`internal`](/problems/internal) | Yes; keep the `request_id` if you report it | -| [`safety_intervention`](/problems/safety_intervention), [`content_policy`](/problems/content_policy) | No — change the request | +## When Cortex itself is unavailable + +| What you see | What it means | What to do | +| --- | --- | --- | +| `Cortex is temporarily unavailable` | Something upstream is down and is being worked on | Retry after a pause. See [`service_unavailable`](/problems/service_unavailable) | +| `No capacity right now` | Every backend that can serve the model is saturated | `A moment usually clears it.` See [`no_capacity`](/problems/no_capacity) | +| `The assistant failed` | The request reached the assistant and came back an error | `Retrying often works.` See [`upstream_failure`](/problems/upstream_failure) | +| `The assistant took too long` | The request was abandoned rather than left hanging | A shorter prompt or a faster model usually gets through. See [`upstream_timeout`](/problems/upstream_timeout) | +| `Something broke on our side` | A Cortex fault, already recorded | Retry, and quote the reference id if you get in touch. See [`internal`](/problems/internal) | +| `You are offline. Messages wait here until you are back.` | Nothing was sent | It resumes when the connection returns. The banner clears itself | +| `Cortex is taking a short break` with `We'll be right back` | A maintenance window | The screen shows `Time remaining` and ends on `Coming back now`. Check the status page for the real window | -## System-wide outages +<Note> +If Chat, Code and Bot are all failing at once, check [status.cortex.foundation](https://status.cortex.foundation) before filing anything. Planned windows and incidents are posted there. See [System status](/reference/status). +</Note> -If Chat, Code, Bot, or the API are all failing at once, check **[status.cortex.foundation](https://status.cortex.foundation)** before filing a bug. Fleet incidents and maintenance windows are posted there — see [System status](/status). +## Reporting it -## Reporting a problem +Three codes may add a second detail line under the message: `validation_failed`, `bad_request` and `invalid_state`. Field-level messages are short and specific, such as `This is required.`, `This is longer than allowed.` and `This is not one of the accepted values.` -Keep the `request_id` from the error, the time, and the surface you were on. From the CLI, `cortex feedback bug "what happened" --include-logs` attaches diagnostics. +When you report something, keep the reference id from the error, the time, and the surface you were on. Signed-in members file a bug from inside Cortex with **Report a bug**, next to **Settings** in the sidebar footer. Guests cannot: reporting needs an account. Screenshots must be PNG, JPEG or WebP, up to five, 4 MB each, and going over that answers `Each screenshot can be at most 4 MB.` or `Screenshots must be PNG, JPEG or WebP.` More than five reports, or more than fifteen screenshot uploads, in an hour is refused with `Too many requests`. ## Related -- [Chat troubleshooting](/chat/troubleshooting) — turns, files, models, and connections. -- [Code troubleshooting](/code/troubleshooting) — gates, Reconnect, and runtimes. -- [Bot troubleshooting](/bot/troubleshooting) — computers, parked steps, and routines. -- [CLI troubleshooting](/cli/troubleshooting) — the terminal. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. +- [Problem catalog](/problems) +- [Report a bug](/getting-started/report-a-bug) +- [Plans and quotas](/getting-started/plans) +- [Accounts and sign-in](/getting-started/accounts) +- [System status](/reference/status) +- [Frequently asked questions](/getting-started/faq) diff --git a/getting-started/two-factor.mdx b/getting-started/two-factor.mdx new file mode 100644 index 0000000..9847922 --- /dev/null +++ b/getting-started/two-factor.mdx @@ -0,0 +1,111 @@ +--- +title: "Two-factor authentication" +description: "Link an authenticator app to your Cortex account. The second factor confirms data export and account deletion." +icon: "lock" +--- + +Two-factor authentication in Cortex is a confirmation step in front of the two actions you cannot undo: exporting everything Cortex holds for your account, and deleting the account. It lives in **Settings → Data & privacy → Two-factor authentication** and uses an authenticator app that generates a six-digit code. There is no SMS option and no security-key option. + +This page covers what the second factor actually protects today, how to enrol an authenticator, how the confirmation behaves when you export or delete, what happens if you lose the device, and which parts of the surrounding screen are drawn but not available yet. Read it before you rely on two-factor as a sign-in defence, because that is not what it is here. + +<Warning> +The sign-in dialog has no second-factor field. Enrolling an authenticator does not add a challenge to sign-in, and it does not stop someone signing in with your email code or your linked Google or Apple account. If your organisation requires a second factor at sign-in, it runs during the identity step, not in Cortex. See [Accounts and sign-in](/getting-started/accounts). +</Warning> + +## What the second factor protects + +Both actions under **Your data** in **Settings → Data & privacy** are gated: + +| Action | What it needs | +| --- | --- | +| **Export my data** | An enrolled authenticator, plus a recent confirmation | +| **Delete all data** | An enrolled authenticator, plus a recent confirmation | + +If either is missing, the action refuses rather than half-running, and the product says `Confirm two-factor authentication, then try again.` There is no way to skip the second factor on export or deletion. + +A confirmation lasts **fifteen minutes** and is bound to your account and to the session that asked for it. A code you confirmed in another tab on another machine does not unlock this one. Guests never meet the gate, because a guest has no account to export or delete, and the row reads `Two-factor authentication is available after you sign in.` + +## Enrol an authenticator + +You need an authenticator app on a phone or a computer. The enrolment challenge is valid for **ten minutes**, so finish it in one sitting. + +<Steps> + <Step title="Open the row"> + Go to **Settings → Data & privacy → Two-factor authentication**. Before enrolment the row reads `Not set up yet. Add an authenticator app before you export or delete this account.` + </Step> + <Step title="Choose Add authenticator"> + Select **Add authenticator**. Cortex draws an `Authenticator QR code`. + </Step> + <Step title="Scan, or type the key"> + Scan the code in your authenticator app. The screen says `Scan this code in your authenticator app. Cortex never shows the secret as text.` If your device cannot scan, use `Cannot scan? Enter this key:` and type the key by hand. + </Step> + <Step title="Confirm the code"> + Type the six digits your app shows into **Authenticator code** and choose **Confirm code**. The code refreshes every thirty seconds, so use the current one. + </Step> + <Step title="Check the result"> + The row then reads `An authenticator app is already linked to this account.` + </Step> +</Steps> + +## Confirm an export or a deletion + +Once an authenticator is linked, the two destructive actions ask for a code the first time you use them, and then stay unlocked for fifteen minutes. + +<Steps> + <Step title="Start the action"> + Choose **Export my data** or **Delete all data** under **Your data**. + </Step> + <Step title="Confirm to continue"> + When Cortex needs a fresh confirmation it shows **Confirm to continue** with an `Authenticator code` field. Enter the current code and choose `Confirm code`. + </Step> + <Step title="Finish the action"> + Export assembles the file while you wait and confirms `Download started — a JSON copy of what we hold for this account.` Deletion asks once more in its own dialog, then reports `Deletion requested — your data will be permanently erased within 30 days. Signing in again during that time cancels it.` + </Step> +</Steps> + +If the confirmation has expired or was never given, the action stops with `Confirm two-factor authentication, then try again.` Nothing is exported and nothing is scheduled. See [Data and privacy](/getting-started/data-and-privacy) for what the export contains and how the deletion grace period works. + +## If you lose the authenticator + +Losing the device does not lock you out of Cortex. Sign-in does not ask for a second factor, so you can still open Chat, Code and Bot exactly as before. What you lose is the ability to export or delete your data until you can produce a code again. + +Cortex has no self-service fallback for this today: **Show recovery codes** answers `Recovery codes are not available on this deployment.`, and there is no control that removes a linked authenticator. Practical consequence: use your authenticator app's own backup or device-transfer feature, and keep it working before you need it. + +## What is not available yet + +The two-factor row is drawn beside several controls that are not wired on this deployment. The product says so in place rather than failing when you press them. + +| Control | What you get instead | +| --- | --- | +| **Add a passkey** | `Passkeys are not available on this deployment.` | +| **Show recovery codes** | `Recovery codes are not available on this deployment.` | +| **Login alerts** (`Email when a new device or location signs in.`) | Toggle drawn on and disabled: `Login alerts are not available on this account yet.` | +| **Lockdown mode** (`Ends all sessions and blocks new logins until you unlock with recovery codes or verified email.`) | A confirm dialog exists, but the account reports `Lockdown is not available on this account yet.` | +| **API keys** | `Create, rotate and revoke stay disabled until the account API stores only hashes and can deny expired keys immediately.` There are no programmatic keys today. | + +SMS codes and hardware security keys are not offered at all. An authenticator app is the only second factor. + +## States you may see + +| State | What the row says | +| --- | --- | +| Loading | `Checking two-factor status…` | +| Guest | `Two-factor authentication is available after you sign in.` | +| Session expired | `Sign in again to manage two-factor authentication.` | +| Not allowed for this session | `Two-factor authentication is not available for this session.` | +| Server unreachable | `The server could not be reached. Try again in a moment.` | +| Status could not be read | `Two-factor status could not be loaded.` | +| Not enrolled | `Not set up yet. Add an authenticator app before you export or delete this account.` | +| Enrolled | `An authenticator app is already linked to this account.` | +| Confirmation needed | `Confirm to continue` | +| Gate hit on export or deletion | `Confirm two-factor authentication, then try again.` | + +A status that could not be read is never treated as "enrolled": the gate stays closed and the action refuses. + +## Related + +- [Accounts and sign-in](/getting-started/accounts) - sign-in methods, and why the dialog has no code field. +- [Data and privacy](/getting-started/data-and-privacy) - export, deletion, cookies, memory and retention. +- [Settings](/getting-started/settings) - where the Data & privacy tab sits among the seven tabs. +- [Security and privacy reference](/reference/security-and-privacy) - what Cortex stores and what it does not claim. +- [Troubleshooting](/getting-started/troubleshooting) - other gates and refusals across the product. diff --git a/getting-started/what-is-cortex.mdx b/getting-started/what-is-cortex.mdx index 9eb80cf..2838a32 100644 --- a/getting-started/what-is-cortex.mdx +++ b/getting-started/what-is-cortex.mdx @@ -1,75 +1,113 @@ --- title: "What is Cortex" -description: "Four products and a CLI behind one account on cortex.foundation — Chat, Code, Bot, Design, and the Cortex CLI." -image: "/images/banners/getting-started.png" -keywords: ["overview", "products", "comparison"] +description: "One account on cortex.foundation behind Chat, Code, Bot, the CLI, Design and Security, running on the Cortex models." +icon: "circle-info" --- -Cortex is built by the Cortex Foundation, a research-first lab. The products share one account, one domain, and one set of models. Use **Chat** for conversation and research, **Code** for a repository, **Bot** for an always-on teammate with its own computer, **Design** for persistable canvases, and the **CLI** to drive Code from a terminal. +Cortex is built by the Cortex Foundation. It is not a single app but a small family of applications that share one account, one domain and one set of models: **Cortex Chat** for conversation and research, **Cortex Code** for work inside a repository, **Cortex Bot** for an agent with a computer of its own, **Cortex CLI** for the terminal, **Cortex Design** for canvases, and **Cortex Security** for reviewing pull requests where they already live. -<Frame caption="cortex.foundation/about — the Foundation builds Cortex Chat, Cortex Code, and Cortex Bot."> - <img src="/images/product/about.png" alt="About Cortex — Making AI systems worthy of reliance; the Foundation builds Cortex Chat, Cortex Code, and Cortex Bot" /> -</Frame> +This page is the map: the applications and where each opens, what one account means in practice, the models behind them, how the browser differs from the desktop app and the terminal, the hostnames you will meet, and what Cortex does not do yet. -## The products +## The applications -| Product | What you open | Who can use it | Guide | +| Application | Where you open it | Who can use it | Guide | | --- | --- | --- | --- | -| **Cortex Chat** | `cortex.foundation` | Everyone, including before you sign in | [Chat](/chat) | -| **Cortex Code** | `/code` in the web app, the desktop app, or the CLI | Signed-in members | [Code](/code) | -| **Cortex Bot** | `/bot` in the web app, or the Bot desktop app | Signed-in members | [Bot](/bot) | -| **Cortex CLI** | `cortex` in a terminal | Signed-in members | [CLI](/cli) | -| **Cortex Design** | The Design desktop app | Signed-in members | [Design](/design) | -| **Cortex Security** | `/code/security` in the web app | Signed-in members with a GitHub repository | [Cortex Security](/code/security) | +| **Cortex Chat** | `cortex.foundation` | Everyone, including before you sign in | [Chat](/chat/index) | +| **Cortex Code** | The web app, the desktop app, or the CLI | Invited, signed-in accounts | [Code](/code/index) | +| **Cortex Bot** | The web app | Invited, signed-in accounts | [Bot](/bot/index) | +| **Cortex CLI** | `cortex` in a terminal | Signed-in accounts | [CLI](/cli/index) | +| **Cortex Design** | The Cortex Design desktop app | Signed-in accounts | [Design](/design/index) | +| **Cortex Security** | The security pages inside Cortex Code | Signed-in accounts with a repository | [Security](/security/index) | -Chat works unsigned. Everything else needs an account, so that a guest session can never create a grant, a bot, or a session it could not come back to revoke. +Chat, Code and Bot sit inside one shell. The sidebar, the notification bell and Settings are the same objects in all three, and **Switch product** moves between them without reloading or losing what is on screen. -## When to use which +They are deliberately not the same shape. Chat is a transcript. A Code session is a timeline of work with approvals and a diff, not a chat with a different icon. A Bot has a desktop you can watch. A Design canvas is a board, not a markdown sidecar. Read [How Chat works](/chat/how-it-works), [How Code works](/code/how-it-works) and [How Bot works](/bot/how-it-works) for the shape of each one. -| You want to… | Use | -| --- | --- | -| Ask questions, write, research with citations, generate or check images | **Chat** | -| Change a repository, run tests, open a pull request | **Code** | -| Delegate ongoing work to an agent that browses, clicks, and runs on a schedule | **Bot** | -| Work on code from your own terminal, in scripts, or in CI | **CLI** | -| Lay out frames, notes, and a component library on a board | **Design** | -| Review GitHub pull requests in place | **Cortex Security** | +**Cortex Bounty** is a programme rather than an application you open. It has its own section covering how to pair a hotkey, how to file a report and how verdicts are scored: see [Cortex Bounty](/bounty/index). -Chat does not run Code's workspace shell or Bot's computer. Code sessions are a timeline of work, not a chat transcript. Design canvases are not Chat markdown sidecars. Each product keeps its own shape on purpose — see [How Chat works](/chat/how-it-works), [How Code works](/code/how-it-works), and [How Bot works](/bot/how-it-works). +## One account, several surfaces -## Models +One sign-in on `cortex.foundation` opens everything: Chat, Code, Bot, Security, the desktop apps and the CLI. There are no separate logins and nothing to link. -Every product runs on Cortex models. In Chat you pick per conversation from the composer chip: +Chat is the only application that works before you sign in. Everything else is for signed-in accounts, and the rule behind that is worth knowing because it explains most of the differences you will run into: a guest session cannot be signed back into later to withdraw a grant, so it is never allowed to make one. -| Model | Status | Notes | +| | Guest | Signed-in account | | --- | --- | --- | -| **Cortex 1 Mini** | Preview | Default for new chats. 262K context, reasoning, tools. | -| **Cortex Teutonic-1** | Preview | Second public preview, under active training. 32.8K context, reasoning, tools. | -| **Cortex-Image-1** | Preview | Image generation for Chat. Built on NVIDIA Cosmos. | +| Chat conversations | Yes, within the guest allowance | Yes | +| Projects, Library, memory, a plan | No | Yes | +| Connected apps and MCP servers | No | Yes | +| Cortex Code and Cortex Bot | No | Yes, once invited | +| Cortex Design canvases | No | Yes | +| The CLI and the desktop apps | No | Yes | +| Two-factor authentication, export, deletion | No | Yes | + +Guest conversations live in the browser session, so sign in before closing the tab if you want to keep one. [Accounts and sign-in](/getting-started/accounts) has the full comparison and the exact wording of every gate. + +<Note> +Cortex is per account today. There are no teams, no organisations, no invitations to a shared workspace and nothing to administer for other people. Role and directory controls you may see in Settings describe an organisation you cannot create yet. +</Note> -The CLI shows models under English product names — **Cortex Mini 1**, **Cortex 1**, **Cortex Max 1** — and lets you tune reasoning effort per session. Details: [Chat models](/chat/models) and [CLI modes](/cli/modes-and-permissions). +## The models -## Language +Every application runs on Cortex models. In Chat you choose per conversation from the composer, and you set the default under **Settings** then **Models**. + +| Model | Status | What it is for | +| --- | --- | --- | +| **Cortex 1 Mini** | Preview | The general model Cortex serves today, and the default for new chats. A 262,144-token context and up to 32,768 tokens of output. | +| **Cortex Teutonic-1** | Preview | A second public model, under active training. A 32,768-token context and up to 16,384 tokens of output. | +| **Cortex-Image-1** | Preview | Image generation inside Cortex Chat. | + +All three are previews, and all three are available from the Free plan upwards, so no published model is plan-gated today. Earlier model names were withdrawn from the public catalogue and are no longer served. [Models](/reference/models) is the current list. + +## Browser, desktop and terminal + +| Surface | What it gives you | +| --- | --- | +| The browser | Chat, and the cloud runtimes behind Code and Bot. Nothing to install. | +| The desktop app | Everything the browser does, plus a host on your own machine or on a server you own, a floating companion with a global **Quick Chat**, **Appshots** capture, and optional **Computer history** recording. | +| The Cortex Design desktop app | Editing canvases, their versions and the reusable library. | +| The CLI | The same Code sessions from a terminal, a script or a pipeline. | -English is the source of truth for interface copy. The web app is localized into French, Spanish, German, Japanese, Simplified Chinese, Brazilian Portuguese, and Korean; switch under **Settings → General → Language**. Model prompts stay in English. Product names are never translated. +A local host is not a missing browser feature: it exists only where the code can actually run. **Computer history** is off by default, records times only and never screenshots or audio, and never logs private browsing. [Ways to run Cortex](/getting-started/downloads) compares the surfaces. -<Frame caption="The same Chat home in French. Product names — Chat, Code, Bot — stay untranslated."> - <img src="/images/product/chat-home-fr.png" alt="Cortex Chat home in French — Bonjour, Nouveau chat, Projets, Artefacts, Personnaliser" /> -</Frame> +## Plans + +There are five plan names: **Guest** for browsing without an account, then **Free**, **Go**, **Plus** and **Pro**. A plan is a named ceiling on a fixed window, and the two windows Cortex enforces on every turn are messages today and messages this month. When one runs out, Cortex says so and shows when it resets rather than quietly degrading the answer. + +Plan details, the exact numbers and how a limit reads on screen are on [Plans and quotas](/getting-started/plans). Note that **Settings** then **Plan & billing** lists the plans and marks the one you are on, but this deployment cannot complete a plan change in the app yet: there is no checkout, no customer portal and no invoice to download, and **Billing history** stays empty. + +## Interface language + +The interface is available in eight languages: English, French, Spanish, German, Japanese, Simplified Chinese, Brazilian Portuguese and Korean. The picker lists each one in its own language. Switch under **Settings** then **General** then **Language**. + +English is the source of truth and is unprefixed. Every other language is a path prefix, so the French site lives under `/fr`. Your first visit reads the browser's language once, and after that the choice you saved wins and is remembered for a year. Model prompts stay in English, and the product names are never translated. See [Interface language](/getting-started/language). ## Hostnames | Host | What it serves | | --- | --- | -| `cortex.foundation` | Web app, public product pages, news, legal | +| `cortex.foundation` | The web app, the public product pages, news and legal | | `software.cortex.foundation` | CLI installers and release manifests | -| `releases.cortex.foundation` | Desktop app downloads and updater feed | -| `api.cortex.foundation` | The API the apps and the CLI talk to | -| `docs.cortex.foundation` | This site | +| `releases.cortex.foundation` | Desktop app downloads and the updater feed | +| `api.cortex.foundation` | The interface the apps and the CLI talk to | +| `docs.cortex.foundation` | This documentation site | +| `status.cortex.foundation` | Live availability, incidents and maintenance | + +## What Cortex does not do yet + +Being clear about the gaps saves you looking for controls that are not there. + +- There is no public model-inference API, no endpoints, no software development kits and no programmatic keys. See [Platform API](/reference/platform-api). +- There are no teams or shared workspaces, as above. +- Plan changes cannot be completed in the app on this deployment. +- Passkeys and recovery codes are drawn in Settings but report that they are not available on this deployment. An authenticator app is the second factor that works. See [Two-factor authentication](/getting-started/two-factor). +- Cortex claims no certification. The **Compliance** section inside **Settings** then **Data & privacy** lists each framework with its honest status, and a status is not a certificate. See [Security and privacy](/reference/security-and-privacy). -## Next +## Related -1. [Quickstart](/getting-started/quickstart) — a first Chat, then the other surfaces. -2. [Accounts](/getting-started/accounts) — guest versus member. -3. [Plans](/getting-started/plans) — what each plan includes and how quotas behave. -4. [Settings](/getting-started/settings) — theme, language, shortcuts, models, privacy. +- [Quickstart](/getting-started/quickstart) +- [Which product do I need?](/getting-started/choose-a-product) +- [Accounts and sign-in](/getting-started/accounts) +- [Plans and quotas](/getting-started/plans) +- [Ways to run Cortex](/getting-started/downloads) +- [Glossary](/getting-started/glossary) diff --git a/images/README.md b/images/README.md deleted file mode 100644 index 19a3bbc..0000000 --- a/images/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Icon, card, and product media - -Section tops and home cards use **banner** illustrations: cream paper, ink -line, brand green `#1F4945`. Banners are heroes and Mintlify `Card img` -slots, not product UI. Doodles remain as small icon stand-ins. - -Guide heroes that depict the product are **real Cortex screenshots**: - -- `banners/*.png` — section / home cards (Chat, Code, Bot, Design, …) -- `product/*.png` — live Chat / Code / Bot / Settings / public-page captures, one per guide -- `cli/` — vendored from CortexLM/cli: the README GIF and the Designer runtime pack (`cli/runtime/`) - -Do not add abstract product-window SVGs. `frames/*.svg` is retired. -Do not add Ask Assistant chrome or pixel plates. Never show the same -product capture on two pages; capture the surface instead. - -| File | Slot | -| --- | --- | -| `banners/getting-started.png` | Home / Get started card | -| `banners/chat.png` | Chat hub + Chat quickstart card | -| `banners/code.png` | Code hub card | -| `banners/bot.png` | Bot hub card | -| `banners/design.png` | Design hub card | -| `banners/security.png` | Security hero | -| `banners/changelog.png` | Changelog hero | -| `doodle-getting-started.svg` | Open book, compass, leaf | -| `doodle-chat.svg` | Overlapping speech bubbles, leaf | -| `doodle-code.svg` | Editor frame, `< \| >` | -| `doodle-bot.svg` | Robot head, green gear | -| `doodle-design.svg` | Framed canvas, pencil, leaf | -| `doodle-security.svg` | Shield, lock, vine | -| `doodle-changelog.svg` | Notebook, up arrows | -| `icon-*.svg` | Same art, kept for older `icon-*` references | -| `card-chat.svg` … `card-design.svg` | How-it-works illustrations (same doodles) | -| `product/*.png` | Live app captures, one distinct surface per page — see `product/README.md` | -| `cli/intro.gif` | CLI desktop demo (vendored from CortexLM/cli) | -| `cli/runtime/*.png` | Designer runtime pack — one distinct TUI state per frame, see `cli/README.md` | - -Home, Chat hub, Get started, and other section cards use the `banners/*` -paths. Green is focus and frame only — never a filled meadow CTA. No violet. diff --git a/images/banners/README.md b/images/banners/README.md deleted file mode 100644 index bddece8..0000000 --- a/images/banners/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Section banner cards - -Cream / ink / `#1F4945` illustration cards for Mintlify `Card img` and -page `image` frontmatter. These are **section heroes and home cards**, -not product UI. Live app captures stay in `images/product/`. - -Do not add Ask Assistant chrome or pixel plates here. - -| File | Section | -| --- | --- | -| `getting-started.png` | Get started / home | -| `chat.png` | Chat hub and Chat quickstart | -| `code.png` | Code hub | -| `bot.png` | Bot hub | -| `design.png` | Design hub | -| `security.png` | Security | -| `changelog.png` | Changelog | diff --git a/images/banners/bot.png b/images/banners/bot.png deleted file mode 100644 index 41d45f2..0000000 Binary files a/images/banners/bot.png and /dev/null differ diff --git a/images/banners/changelog.png b/images/banners/changelog.png deleted file mode 100644 index 1d3e3fc..0000000 Binary files a/images/banners/changelog.png and /dev/null differ diff --git a/images/banners/chat.png b/images/banners/chat.png deleted file mode 100644 index a0707b3..0000000 Binary files a/images/banners/chat.png and /dev/null differ diff --git a/images/banners/code.png b/images/banners/code.png deleted file mode 100644 index c75859a..0000000 Binary files a/images/banners/code.png and /dev/null differ diff --git a/images/banners/design.png b/images/banners/design.png deleted file mode 100644 index 3be573e..0000000 Binary files a/images/banners/design.png and /dev/null differ diff --git a/images/banners/getting-started.png b/images/banners/getting-started.png deleted file mode 100644 index 0cd08d5..0000000 Binary files a/images/banners/getting-started.png and /dev/null differ diff --git a/images/banners/security.png b/images/banners/security.png deleted file mode 100644 index 58c6cdb..0000000 Binary files a/images/banners/security.png and /dev/null differ diff --git a/images/card-bot.svg b/images/card-bot.svg deleted file mode 100644 index e8e92bd..0000000 --- a/images/card-bot.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#F0E6B0"/> - - <rect x="108" y="48" width="104" height="92" rx="28" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M160 48V34" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="160" cy="30" r="6" fill="#1F4945" stroke="#1C1917" stroke-width="1.6"/> - <circle cx="136" cy="88" r="7" fill="#1C1917"/> - <circle cx="184" cy="88" r="7" fill="#1C1917"/> - <path d="M140 114c8 10 32 10 40 0" fill="none" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="214" cy="78" r="16" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <circle cx="214" cy="78" r="6" fill="#1F4945"/> - <path d="M214 62v6M214 88v6M198 78h6M224 78h6M203 67l4 4M221 85l4 4M203 89l4-4M221 71l4-4" stroke="#1F4945" stroke-width="1.6" stroke-linecap="round"/> - -</svg> diff --git a/images/card-chat.svg b/images/card-chat.svg deleted file mode 100644 index 20ad0eb..0000000 --- a/images/card-chat.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D2DC"/> - - <path d="M92 52h72c8 0 14 6 14 14v36c0 8-6 14-14 14H132l-16 16v-16H92c-8 0-14-6-14-14V66c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M52 40h78c8 0 14 6 14 14v34c0 8-6 14-14 14H92l-14 14v-14H52c-8 0-14-6-14-14V54c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M78 68c8-12 18-14 22-4-8 2-12 10-14 18-6-4-8-8-8-14z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M84 72c2 4 5 8 7 12" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/card-code.svg b/images/card-code.svg deleted file mode 100644 index 7109261..0000000 --- a/images/card-code.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E8CDB8"/> - - <rect x="70" y="42" width="180" height="108" rx="10" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <circle cx="88" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="102" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="116" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <path d="M78 72h164" stroke="#1C1917" stroke-width="1.6"/> - <path d="M128 92l-22 22 22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M192 92l22 22-22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <rect x="156" y="88" width="8" height="52" rx="2" fill="#1F4945"/> - -</svg> diff --git a/images/card-design.svg b/images/card-design.svg deleted file mode 100644 index e87c3de..0000000 --- a/images/card-design.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D6C6"/> - - <rect x="96" y="36" width="128" height="108" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M168 58l28 72-18-6-10-66z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2" stroke-linejoin="round"/> - <path d="M168 58l-8 8 10 66" stroke="#1C1917" stroke-width="1.4"/> - <rect x="166" y="52" width="12" height="10" rx="1" fill="#1F4945" stroke="#1C1917" stroke-width="1.2"/> - <path d="M124 92c12-20 26-24 32-8-14 4-20 18-24 32-8-8-12-16-8-24z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M132 96c4 6 8 14 10 20" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/cli/README.md b/images/cli/README.md deleted file mode 100644 index 1d167e9..0000000 --- a/images/cli/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# CLI canon media - -Vendored from [`CortexLM/cli`](https://github.com/CortexLM/cli). Real renders of -the shipped TUI — not SVG mocks, not invented terminal art. Each file is used on -exactly one page; no two files share a sha256. - -## `intro.gif` - -`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 - -Headless `MockTerminal` renders of the live session chrome, vendored byte-for-byte -from CortexLM/cli tip `4d41ef362481ec816ac395e0e64fe6a54327de14` -(`[feat] /goal persisted long-horizon workflows (#54)`): - -``` -https://raw.githubusercontent.com/CortexLM/cli/4d41ef362481ec816ac395e0e64fe6a54327de14/docs/media/tui-lock-v2/runtime/120x40/<name>.png -https://raw.githubusercontent.com/CortexLM/cli/4d41ef362481ec816ac395e0e64fe6a54327de14/docs/media/tui-lock-v2/runtime/40x12/<name>.png -``` - -The layout mirrors the source: `runtime/120x40/` (1232×912) and `runtime/40x12/` -(432×296). Inky background, dual-hairline composer, model chip on the border, -accent `#1F4945`. The full pack is 82 boards at 120×40 and 36 at 40×12; these are -the ones the guides use. `custom.css` shows 40×12 boards at their natural width. - -### 120×40 - -| File | State | Used on | -| --- | --- | --- | -| `composer-hover.png` | Session composer, pointer hovering | `cli/index` | -| `welcome-cortex.png` | Welcome splash v0.1.10, empty composer | `cli/install` | -| `login.png` | Sign-in picker: browser or API key | `cli/sign-in` | -| `login-waiting.png` | Waiting for browser, device code shown | `cli/sign-in` | -| `first-run-tips.png` | Welcome plus the first-run tips panel | `cli/quickstart` | -| `session-thinking-live.png` | Thinking · 3s, follow-up composer | `cli/quickstart` | -| `composer-empty.png` | Empty Agent composer | `cli/tui` | -| `composer-typing.png` | Composer with a prompt being typed | `cli/tui` | -| `tool-tiles.png` | Grouped Read / Grep / Shell tool rows | `cli/tui` | -| `diff-hunk.png` | Edit tile with a unified diff | `cli/tui` | -| `queue.png` | Two queued follow-ups behind a running Shell | `cli/tui` | -| `interrupt-stopped.png` | × Stopped after Esc | `cli/tui` | -| `cloud-handoff.png` | `&` hand-off to Cortex Cloud | `cli/tui` | -| `slash-palette.png` | Slash palette home, `/goal` after `/plan` | `cli/slash-commands` | -| `slash-model-typed.png` | Palette filtered by `/model` | `cli/slash-commands` | -| `usage.png` | `/usage` meters | `cli/slash-commands` | -| `mode-plan.png` | Plan mode, drafted plan, Plan · no edits composer | `cli/modes-and-permissions` | -| `plan-confirm.png` | Implement this plan? picker | `cli/modes-and-permissions` | -| `permission-prompt.png` | Inline approval, four numbered options | `cli/modes-and-permissions` | -| `permissions-picker.png` | `/permissions`: Smart, Read-only, Full access | `cli/modes-and-permissions` | -| `sandbox-deny.png` | × Sandbox denied with three options | `cli/modes-and-permissions` | -| `model-effort-medium.png` | `/model` effort radios, Medium selected | `cli/modes-and-permissions` | -| `goal-chip-active.png` | Composer chip Goal · 2/8 | `cli/goal` | -| `goal-chip-done.png` | Composer chip Goal · done | `cli/goal` | -| `resume-picker.png` | `/resume` session picker | `cli/sessions` | -| `clear-confirm.png` | `/clear` confirmation | `cli/sessions` | -| `shortcuts-overlay.png` | Ctrl+X shortcuts overlay | `cli/keyboard` | -| `permission-prompt-hover.png` | Approval prompt, pointer over a row | `cli/keyboard` | -| `config-tree.png` | `/config` read-only tree | `cli/configuration` | -| `settings-appearance.png` | `/settings` → Appearance | `cli/configuration` | -| `mcp-servers.png` | `/mcp` server manager | `cli/extend` | -| `skills.png` | `/skills` picker | `cli/extend` | -| `plugins.png` | `/plugins` manager | `cli/extend` | -| `error-unavailable.png` | The coding service is temporarily unavailable | `cli/troubleshooting` | -| `quota-exhausted.png` | × Agent quota exhausted, held composer | `cli/troubleshooting` | -| `diagnostics.png` | Diagnostics row after an edit | `cli/troubleshooting` | - -### 40×12 - -Compact boards. Used where another product's page points at the CLI, and once -on `cli/tui` to show the chrome folding into a small terminal. No -`permission-prompt-hover` exists at this size in the source. - -| File | State | Used on | -| --- | --- | --- | -| `composer-empty.png` | Empty composer at 40×12 | `cli/tui` (Display) | -| `welcome-cortex.png` | Welcome splash at 40×12 | `getting-started/downloads` | -| `composer-typing.png` | Typing a prompt at 40×12 | `code/cli` | -| `composer-hover.png` | Composer, pointer hovering, at 40×12 | `code/desktop` | -| `slash-palette.png` | Palette showing `/plan` and `/goal` at 40×12 | `code/interactions` | -| `goal-chip-active.png` | Goal · 2/8 chip at 40×12 | `code/how-it-works` | -| `permission-prompt.png` | Approval prompt at 40×12 | `security/overview` | - -Refresh from the CLI repository rather than editing pixels here. When a new state -is needed, take the matching board from the pack and add a row above. Not -vendored on purpose: `login-success.png` (shows a real account address). The -earlier macOS-desktop composites (`splash`, `working`, `composer`, `model`, -`palette`, `shell`) were retired in favour of this pack. diff --git a/images/cli/intro.gif b/images/cli/intro.gif deleted file mode 100644 index 095aac9..0000000 Binary files a/images/cli/intro.gif and /dev/null differ diff --git a/images/cli/runtime/120x40/clear-confirm.png b/images/cli/runtime/120x40/clear-confirm.png deleted file mode 100644 index d78bad9..0000000 Binary files a/images/cli/runtime/120x40/clear-confirm.png and /dev/null differ diff --git a/images/cli/runtime/120x40/cloud-handoff.png b/images/cli/runtime/120x40/cloud-handoff.png deleted file mode 100644 index 5f10804..0000000 Binary files a/images/cli/runtime/120x40/cloud-handoff.png and /dev/null differ diff --git a/images/cli/runtime/120x40/composer-empty.png b/images/cli/runtime/120x40/composer-empty.png deleted file mode 100644 index 9740f22..0000000 Binary files a/images/cli/runtime/120x40/composer-empty.png and /dev/null differ diff --git a/images/cli/runtime/120x40/composer-hover.png b/images/cli/runtime/120x40/composer-hover.png deleted file mode 100644 index 98c1a7b..0000000 Binary files a/images/cli/runtime/120x40/composer-hover.png and /dev/null differ diff --git a/images/cli/runtime/120x40/composer-typing.png b/images/cli/runtime/120x40/composer-typing.png deleted file mode 100644 index 22c297f..0000000 Binary files a/images/cli/runtime/120x40/composer-typing.png and /dev/null differ diff --git a/images/cli/runtime/120x40/config-tree.png b/images/cli/runtime/120x40/config-tree.png deleted file mode 100644 index 9ea65fb..0000000 Binary files a/images/cli/runtime/120x40/config-tree.png and /dev/null differ diff --git a/images/cli/runtime/120x40/diagnostics.png b/images/cli/runtime/120x40/diagnostics.png deleted file mode 100644 index 454cf05..0000000 Binary files a/images/cli/runtime/120x40/diagnostics.png and /dev/null differ diff --git a/images/cli/runtime/120x40/diff-hunk.png b/images/cli/runtime/120x40/diff-hunk.png deleted file mode 100644 index 1d03599..0000000 Binary files a/images/cli/runtime/120x40/diff-hunk.png and /dev/null differ diff --git a/images/cli/runtime/120x40/error-unavailable.png b/images/cli/runtime/120x40/error-unavailable.png deleted file mode 100644 index e516653..0000000 Binary files a/images/cli/runtime/120x40/error-unavailable.png and /dev/null differ diff --git a/images/cli/runtime/120x40/first-run-tips.png b/images/cli/runtime/120x40/first-run-tips.png deleted file mode 100644 index a72fd8f..0000000 Binary files a/images/cli/runtime/120x40/first-run-tips.png and /dev/null differ diff --git a/images/cli/runtime/120x40/goal-chip-active.png b/images/cli/runtime/120x40/goal-chip-active.png deleted file mode 100644 index 4569305..0000000 Binary files a/images/cli/runtime/120x40/goal-chip-active.png and /dev/null differ diff --git a/images/cli/runtime/120x40/goal-chip-done.png b/images/cli/runtime/120x40/goal-chip-done.png deleted file mode 100644 index 3b75ce9..0000000 Binary files a/images/cli/runtime/120x40/goal-chip-done.png and /dev/null differ diff --git a/images/cli/runtime/120x40/interrupt-stopped.png b/images/cli/runtime/120x40/interrupt-stopped.png deleted file mode 100644 index f28135d..0000000 Binary files a/images/cli/runtime/120x40/interrupt-stopped.png and /dev/null differ diff --git a/images/cli/runtime/120x40/login-waiting.png b/images/cli/runtime/120x40/login-waiting.png deleted file mode 100644 index 168e390..0000000 Binary files a/images/cli/runtime/120x40/login-waiting.png and /dev/null differ diff --git a/images/cli/runtime/120x40/login.png b/images/cli/runtime/120x40/login.png deleted file mode 100644 index 9b7eaab..0000000 Binary files a/images/cli/runtime/120x40/login.png and /dev/null differ diff --git a/images/cli/runtime/120x40/mcp-servers.png b/images/cli/runtime/120x40/mcp-servers.png deleted file mode 100644 index 032cdfa..0000000 Binary files a/images/cli/runtime/120x40/mcp-servers.png and /dev/null differ diff --git a/images/cli/runtime/120x40/mode-plan.png b/images/cli/runtime/120x40/mode-plan.png deleted file mode 100644 index 8ab0688..0000000 Binary files a/images/cli/runtime/120x40/mode-plan.png and /dev/null differ diff --git a/images/cli/runtime/120x40/model-effort-medium.png b/images/cli/runtime/120x40/model-effort-medium.png deleted file mode 100644 index aefe514..0000000 Binary files a/images/cli/runtime/120x40/model-effort-medium.png and /dev/null differ diff --git a/images/cli/runtime/120x40/permission-prompt-hover.png b/images/cli/runtime/120x40/permission-prompt-hover.png deleted file mode 100644 index e4ea44e..0000000 Binary files a/images/cli/runtime/120x40/permission-prompt-hover.png and /dev/null differ diff --git a/images/cli/runtime/120x40/permission-prompt.png b/images/cli/runtime/120x40/permission-prompt.png deleted file mode 100644 index bea2d6d..0000000 Binary files a/images/cli/runtime/120x40/permission-prompt.png and /dev/null differ diff --git a/images/cli/runtime/120x40/permissions-picker.png b/images/cli/runtime/120x40/permissions-picker.png deleted file mode 100644 index 7d988ce..0000000 Binary files a/images/cli/runtime/120x40/permissions-picker.png and /dev/null differ diff --git a/images/cli/runtime/120x40/plan-confirm.png b/images/cli/runtime/120x40/plan-confirm.png deleted file mode 100644 index d8032c9..0000000 Binary files a/images/cli/runtime/120x40/plan-confirm.png and /dev/null differ diff --git a/images/cli/runtime/120x40/plugins.png b/images/cli/runtime/120x40/plugins.png deleted file mode 100644 index 5a48d81..0000000 Binary files a/images/cli/runtime/120x40/plugins.png and /dev/null differ diff --git a/images/cli/runtime/120x40/queue.png b/images/cli/runtime/120x40/queue.png deleted file mode 100644 index 03bc9bc..0000000 Binary files a/images/cli/runtime/120x40/queue.png and /dev/null differ diff --git a/images/cli/runtime/120x40/quota-exhausted.png b/images/cli/runtime/120x40/quota-exhausted.png deleted file mode 100644 index 6c3b362..0000000 Binary files a/images/cli/runtime/120x40/quota-exhausted.png and /dev/null differ diff --git a/images/cli/runtime/120x40/resume-picker.png b/images/cli/runtime/120x40/resume-picker.png deleted file mode 100644 index 63e5fc5..0000000 Binary files a/images/cli/runtime/120x40/resume-picker.png and /dev/null differ diff --git a/images/cli/runtime/120x40/sandbox-deny.png b/images/cli/runtime/120x40/sandbox-deny.png deleted file mode 100644 index 76e47c4..0000000 Binary files a/images/cli/runtime/120x40/sandbox-deny.png and /dev/null differ diff --git a/images/cli/runtime/120x40/session-thinking-live.png b/images/cli/runtime/120x40/session-thinking-live.png deleted file mode 100644 index 639ebff..0000000 Binary files a/images/cli/runtime/120x40/session-thinking-live.png and /dev/null differ diff --git a/images/cli/runtime/120x40/settings-appearance.png b/images/cli/runtime/120x40/settings-appearance.png deleted file mode 100644 index 1fbeb28..0000000 Binary files a/images/cli/runtime/120x40/settings-appearance.png and /dev/null differ diff --git a/images/cli/runtime/120x40/shortcuts-overlay.png b/images/cli/runtime/120x40/shortcuts-overlay.png deleted file mode 100644 index 48e6c64..0000000 Binary files a/images/cli/runtime/120x40/shortcuts-overlay.png and /dev/null differ diff --git a/images/cli/runtime/120x40/skills.png b/images/cli/runtime/120x40/skills.png deleted file mode 100644 index 9c09bdd..0000000 Binary files a/images/cli/runtime/120x40/skills.png and /dev/null differ diff --git a/images/cli/runtime/120x40/slash-model-typed.png b/images/cli/runtime/120x40/slash-model-typed.png deleted file mode 100644 index f1ed837..0000000 Binary files a/images/cli/runtime/120x40/slash-model-typed.png and /dev/null differ diff --git a/images/cli/runtime/120x40/slash-palette.png b/images/cli/runtime/120x40/slash-palette.png deleted file mode 100644 index 1c15b3f..0000000 Binary files a/images/cli/runtime/120x40/slash-palette.png and /dev/null differ diff --git a/images/cli/runtime/120x40/tool-tiles.png b/images/cli/runtime/120x40/tool-tiles.png deleted file mode 100644 index e94f79a..0000000 Binary files a/images/cli/runtime/120x40/tool-tiles.png and /dev/null differ diff --git a/images/cli/runtime/120x40/usage.png b/images/cli/runtime/120x40/usage.png deleted file mode 100644 index 6312a7d..0000000 Binary files a/images/cli/runtime/120x40/usage.png and /dev/null differ diff --git a/images/cli/runtime/120x40/welcome-cortex.png b/images/cli/runtime/120x40/welcome-cortex.png deleted file mode 100644 index e01678b..0000000 Binary files a/images/cli/runtime/120x40/welcome-cortex.png and /dev/null differ diff --git a/images/cli/runtime/40x12/composer-empty.png b/images/cli/runtime/40x12/composer-empty.png deleted file mode 100644 index 4534bd8..0000000 Binary files a/images/cli/runtime/40x12/composer-empty.png and /dev/null differ diff --git a/images/cli/runtime/40x12/composer-hover.png b/images/cli/runtime/40x12/composer-hover.png deleted file mode 100644 index ccc85e8..0000000 Binary files a/images/cli/runtime/40x12/composer-hover.png and /dev/null differ diff --git a/images/cli/runtime/40x12/composer-typing.png b/images/cli/runtime/40x12/composer-typing.png deleted file mode 100644 index 3b975e9..0000000 Binary files a/images/cli/runtime/40x12/composer-typing.png and /dev/null differ diff --git a/images/cli/runtime/40x12/goal-chip-active.png b/images/cli/runtime/40x12/goal-chip-active.png deleted file mode 100644 index 1424b15..0000000 Binary files a/images/cli/runtime/40x12/goal-chip-active.png and /dev/null differ diff --git a/images/cli/runtime/40x12/permission-prompt.png b/images/cli/runtime/40x12/permission-prompt.png deleted file mode 100644 index 4519e44..0000000 Binary files a/images/cli/runtime/40x12/permission-prompt.png and /dev/null differ diff --git a/images/cli/runtime/40x12/slash-palette.png b/images/cli/runtime/40x12/slash-palette.png deleted file mode 100644 index 8f1d046..0000000 Binary files a/images/cli/runtime/40x12/slash-palette.png and /dev/null differ diff --git a/images/cli/runtime/40x12/welcome-cortex.png b/images/cli/runtime/40x12/welcome-cortex.png deleted file mode 100644 index 08b1ec1..0000000 Binary files a/images/cli/runtime/40x12/welcome-cortex.png and /dev/null differ diff --git a/images/doodle-bot.svg b/images/doodle-bot.svg deleted file mode 100644 index e8e92bd..0000000 --- a/images/doodle-bot.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#F0E6B0"/> - - <rect x="108" y="48" width="104" height="92" rx="28" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M160 48V34" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="160" cy="30" r="6" fill="#1F4945" stroke="#1C1917" stroke-width="1.6"/> - <circle cx="136" cy="88" r="7" fill="#1C1917"/> - <circle cx="184" cy="88" r="7" fill="#1C1917"/> - <path d="M140 114c8 10 32 10 40 0" fill="none" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="214" cy="78" r="16" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <circle cx="214" cy="78" r="6" fill="#1F4945"/> - <path d="M214 62v6M214 88v6M198 78h6M224 78h6M203 67l4 4M221 85l4 4M203 89l4-4M221 71l4-4" stroke="#1F4945" stroke-width="1.6" stroke-linecap="round"/> - -</svg> diff --git a/images/doodle-changelog.svg b/images/doodle-changelog.svg deleted file mode 100644 index 0ce708d..0000000 --- a/images/doodle-changelog.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#EFE8DC"/> - - <rect x="70" y="44" width="100" height="108" rx="6" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M86 44v108M70 64h100M70 80h100M70 96h100" stroke="#1C1917" stroke-width="1.3" opacity="0.7"/> - <circle cx="78" cy="56" r="4" fill="#1F4945"/> - <circle cx="78" cy="72" r="4" fill="#1F4945"/> - <circle cx="78" cy="88" r="4" fill="#1F4945"/> - <path d="M196 120v-52" stroke="#1C1917" stroke-width="2.4" stroke-linecap="round"/> - <path d="M180 86l16-18 16 18" fill="none" stroke="#1F4945" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M236 128v-40" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <path d="M224 104l12-14 12 14" fill="none" stroke="#1F4945" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/> - -</svg> diff --git a/images/doodle-chat.svg b/images/doodle-chat.svg deleted file mode 100644 index 20ad0eb..0000000 --- a/images/doodle-chat.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D2DC"/> - - <path d="M92 52h72c8 0 14 6 14 14v36c0 8-6 14-14 14H132l-16 16v-16H92c-8 0-14-6-14-14V66c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M52 40h78c8 0 14 6 14 14v34c0 8-6 14-14 14H92l-14 14v-14H52c-8 0-14-6-14-14V54c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M78 68c8-12 18-14 22-4-8 2-12 10-14 18-6-4-8-8-8-14z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M84 72c2 4 5 8 7 12" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/doodle-code.svg b/images/doodle-code.svg deleted file mode 100644 index 7109261..0000000 --- a/images/doodle-code.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E8CDB8"/> - - <rect x="70" y="42" width="180" height="108" rx="10" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <circle cx="88" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="102" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="116" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <path d="M78 72h164" stroke="#1C1917" stroke-width="1.6"/> - <path d="M128 92l-22 22 22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M192 92l22 22-22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <rect x="156" y="88" width="8" height="52" rx="2" fill="#1F4945"/> - -</svg> diff --git a/images/doodle-design.svg b/images/doodle-design.svg deleted file mode 100644 index e87c3de..0000000 --- a/images/doodle-design.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D6C6"/> - - <rect x="96" y="36" width="128" height="108" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M168 58l28 72-18-6-10-66z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2" stroke-linejoin="round"/> - <path d="M168 58l-8 8 10 66" stroke="#1C1917" stroke-width="1.4"/> - <rect x="166" y="52" width="12" height="10" rx="1" fill="#1F4945" stroke="#1C1917" stroke-width="1.2"/> - <path d="M124 92c12-20 26-24 32-8-14 4-20 18-24 32-8-8-12-16-8-24z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M132 96c4 6 8 14 10 20" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/doodle-getting-started.svg b/images/doodle-getting-started.svg deleted file mode 100644 index d128f7b..0000000 --- a/images/doodle-getting-started.svg +++ /dev/null @@ -1,17 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#D7E6D4"/> - - <!-- book --> - <path d="M86 46c18 6 34 6 52 0v78c-18 8-36 8-52 0V46z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M86 46c-18 6-34 6-52 0v78c18 8 36 8 52 0V46z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M86 46v78" stroke="#1C1917" stroke-width="2"/> - <!-- leaf --> - <path d="M54 88c10-18 22-22 28-8-12 4-18 16-22 28-8-8-10-14-6-20z" fill="#1F4945" stroke="#1C1917" stroke-width="1.4"/> - <path d="M62 92c4 6 8 12 10 18" stroke="#1C1917" stroke-width="1.2" fill="none"/> - <!-- compass --> - <circle cx="112" cy="96" r="18" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <circle cx="112" cy="96" r="3" fill="#1F4945"/> - <path d="M112 82v6M112 104v6M98 96h6M120 96h6" stroke="#1C1917" stroke-width="1.4"/> - <path d="M112 96 L104 108 L112 90 L120 108 Z" fill="#1F4945" opacity="0.85"/> - -</svg> diff --git a/images/doodle-security.svg b/images/doodle-security.svg deleted file mode 100644 index 1027d17..0000000 --- a/images/doodle-security.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#D5CEE0"/> - - <path d="M160 36c28 10 52 12 64 14v52c0 28-28 48-64 62-36-14-64-34-64-62V50c12-2 36-4 64-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <rect x="142" y="88" width="36" height="28" rx="4" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <path d="M150 88v-10a10 10 0 0 1 20 0v10" fill="none" stroke="#1C1917" stroke-width="2" stroke-linecap="round"/> - <circle cx="160" cy="102" r="3" fill="#1F4945"/> - <path d="M96 70c18-22 36-10 28 8-16 4-22 22-18 36 8-22-4-28-10-44z" fill="#1F4945" opacity="0.9" stroke="#1C1917" stroke-width="1.2"/> - <path d="M224 68c-18-20-36-8-28 10 16 4 22 20 18 34-8-20 4-26 10-44z" fill="#1F4945" opacity="0.9" stroke="#1C1917" stroke-width="1.2"/> - -</svg> diff --git a/images/frames/README.md b/images/frames/README.md deleted file mode 100644 index 919d7a5..0000000 --- a/images/frames/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Retired fake-app plates - -These SVG windows were simplified doodle simulations of the Cortex app. -They are **not** used in public MDX anymore. Do not link them from guides. -Do not run `scripts/generate-docs-frames.py` (it exits unless forced). - -Product UI lives in `images/product/*.png` (live app screenshots) and -`images/cli/` (CortexLM/cli canon). diff --git a/images/frames/approvals.svg b/images/frames/approvals.svg deleted file mode 100644 index 9c07e76..0000000 --- a/images/frames/approvals.svg +++ /dev/null @@ -1,47 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Bot approval Allow Deny Always in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="137" y="87" width="686" height="386" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="140" y="90" width="680" height="380" rx="13" fill="#FAF8F4"/> - <rect x="140" y="90" width="680" height="380" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="142" y="92" width="676" height="376" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="140" y="90" width="680" height="36" rx="13" fill="#F3F0EA"/> - <rect x="140" y="114" width="680" height="12" fill="#F3F0EA"/> - <path d="M140 126 H820" stroke="#211F1C" stroke-width="1"/> - <path d="M140 127 H820" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="158" cy="108" r="5" fill="#C4B8A8"/> - <circle cx="174" cy="108" r="5" fill="#C4B8A8"/> - <circle cx="190" cy="108" r="5" fill="#1F4945"/> - - <text x="480.0" y="113" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Bot · Confirm</text> - - <text x="176" y="178" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="18" font-weight="600" fill="#211F1C">Allow this computer step?</text> - <text x="176" y="210" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#6E6A62">Confirming runs the parked action.</text> - <rect x="176" y="248" width="608" height="72" rx="10" fill="#F3F0EA"/> - <text x="192" y="292" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">grounded_click · Submit form</text> - <rect x="176" y="348" width="140" height="40" rx="8" fill="#211F1C"/> - <text x="246" y="374" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#FAF8F4">Allow</text> - <rect x="328" y="348" width="140" height="40" rx="8" fill="#FAF8F4" stroke="#211F1C"/> - <text x="398" y="374" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#211F1C">Deny</text> - <rect x="480" y="348" width="160" height="40" rx="8" fill="#E1E5DE" stroke="#1F4945" stroke-width="2"/> - <text x="560" y="374" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#1F4945">Always</text> - -</svg> diff --git a/images/frames/bot-computer.svg b/images/frames/bot-computer.svg deleted file mode 100644 index d87a6d6..0000000 --- a/images/frames/bot-computer.svg +++ /dev/null @@ -1,54 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Bot conversation and Computer rail in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="57" y="49" width="846" height="462" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="60" y="52" width="840" height="456" rx="13" fill="#FAF8F4"/> - <rect x="60" y="52" width="840" height="456" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="62" y="54" width="836" height="452" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="60" y="52" width="840" height="36" rx="13" fill="#F3F0EA"/> - <rect x="60" y="76" width="840" height="12" fill="#F3F0EA"/> - <path d="M60 88 H900" stroke="#211F1C" stroke-width="1"/> - <path d="M60 89 H900" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="78" cy="70" r="5" fill="#C4B8A8"/> - <circle cx="94" cy="70" r="5" fill="#C4B8A8"/> - <circle cx="110" cy="70" r="5" fill="#1F4945"/> - - <text x="480.0" y="75" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Bot · Computer</text> - - <rect x="72" y="100" width="473.28" height="396" fill="#F3F0EA"/> - <text x="92" y="132" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Finch</text> - <text x="92" y="156" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Conversation</text> - <rect x="88" y="176" width="441.28" height="56" rx="10" fill="#FAF8F4"/> - <text x="104" y="210" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Open the weekly report and summarise it.</text> - <rect x="88" y="248" width="441.28" height="56" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="104" y="282" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Opening desktop… then I will take a screenshot.</text> - <rect x="553.28" y="100" width="334.71999999999997" height="396" fill="#161412"/> - <text x="569.28" y="132" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#FAF8F4">Computer</text> - <text x="569.28" y="156" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="500" fill="#B0AAA0">Cloud · live desktop</text> - <rect x="565.28" y="176" width="302.71999999999997" height="200" rx="8" fill="#111110" stroke="#1F4945" stroke-width="2"/> - <rect x="581.28" y="196" width="120" height="16" rx="3" fill="#3A3A3A"/> - <rect x="581.28" y="224" width="80" height="48" rx="6" fill="#1F4945" opacity="0.45"/> - <rect x="673.28" y="224" width="80" height="48" rx="6" fill="#3A3A3A"/> - <text x="569.28" y="408" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#FAF8F4">Open desktop</text> - <text x="569.28" y="432" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#B0AAA0">Sleep</text> - <text x="569.28" y="464" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="500" fill="#B0AAA0">Connecting only while starting.</text> - -</svg> diff --git a/images/frames/chat-composer.svg b/images/frames/chat-composer.svg deleted file mode 100644 index 468e31c..0000000 --- a/images/frames/chat-composer.svg +++ /dev/null @@ -1,56 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Cortex Chat composer in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="77" y="61" width="806" height="438" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="80" y="64" width="800" height="432" rx="13" fill="#FAF8F4"/> - <rect x="80" y="64" width="800" height="432" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="82" y="66" width="796" height="428" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="80" y="64" width="800" height="36" rx="13" fill="#F3F0EA"/> - <rect x="80" y="88" width="800" height="12" fill="#F3F0EA"/> - <path d="M80 100 H880" stroke="#211F1C" stroke-width="1"/> - <path d="M80 101 H880" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="98" cy="82" r="5" fill="#C4B8A8"/> - <circle cx="114" cy="82" r="5" fill="#C4B8A8"/> - <circle cx="130" cy="82" r="5" fill="#1F4945"/> - - <text x="480.0" y="87" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Chat</text> - - <rect x="92" y="112" width="200" height="372" fill="#F3F0EA"/> - <path d="M292 112 V484" stroke="#E3DFD7"/> - <text x="108" y="136" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#211F1C">New chat</text> - <text x="108" y="166" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="10" font-weight="600" fill="#6E6A62">TODAY</text> - <rect x="102" y="178" width="180" height="30" rx="7" fill="#E1E5DE"/> - <rect x="102" y="178" width="3" height="30" fill="#1F4945"/> - <text x="116" y="198" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#1F4945">First conversation</text> - <text x="116" y="234" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Attach a brief</text> - <rect x="312" y="128" width="540" height="220" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="332" y="160" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#6E6A62">You</text> - <text x="332" y="184" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">Summarize this launch brief for the team.</text> - <text x="332" y="222" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#1F4945">Cortex</text> - <text x="332" y="246" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">Three outcomes, two risks, one open question.</text> - <text x="332" y="270" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">I used the attached brief — not a pasted URL.</text> - <rect x="312" y="406" width="540" height="64" rx="12" fill="#F3F0EA" stroke="#211F1C" stroke-width="1.2"/> - <rect x="314" y="408" width="536" height="60" rx="10" fill="none" stroke="#E3DFD7"/> - <text x="332" y="444" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Ask a follow-up, or attach another Library file…</text> - <rect x="782" y="422" width="54" height="28" rx="8" fill="#211F1C"/> - <text x="809" y="441" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#FAF8F4">Send</text> - -</svg> diff --git a/images/frames/chat-images.svg b/images/frames/chat-images.svg deleted file mode 100644 index f268c4f..0000000 --- a/images/frames/chat-images.svg +++ /dev/null @@ -1,50 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Image generation card in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="87" y="67" width="786" height="426" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="#FAF8F4"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="92" y="72" width="776" height="416" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="90" y="70" width="780" height="36" rx="13" fill="#F3F0EA"/> - <rect x="90" y="94" width="780" height="12" fill="#F3F0EA"/> - <path d="M90 106 H870" stroke="#211F1C" stroke-width="1"/> - <path d="M90 107 H870" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="108" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="124" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="140" cy="88" r="5" fill="#1F4945"/> - - <text x="480.0" y="93" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Chat · Cortex-Image-1</text> - - <rect x="102" y="118" width="347.76" height="360" rx="10" fill="#F3F0EA"/> - <text x="122" y="154" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Improving prompt…</text> - <rect x="122" y="174" width="307.76" height="280" rx="8" fill="#FAF8F4" stroke="#E3DFD7"/> - <path d="M172 338 C212 278, 262 368, 322 298" stroke="#1F4945" stroke-width="3" fill="none"/> - <circle cx="192" cy="258" r="18" fill="#1F4945" opacity="0.35"/> - <text x="473.76" y="158" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">generate_image</text> - <text x="473.76" y="190" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">A complete English scene</text> - <text x="473.76" y="222" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">queued → generating → Library file</text> - <text x="473.76" y="266" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Size, optional seed, steps 1–50</text> - <text x="473.76" y="294" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Free and Guest: images_per_day quota</text> - <text x="473.76" y="334" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Built on NVIDIA Cosmos</text> - <text x="473.76" y="366" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Empty cluster URL fails closed</text> - <text x="473.76" y="394" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">before any quota is spent.</text> - -</svg> diff --git a/images/frames/chat-projects.svg b/images/frames/chat-projects.svg deleted file mode 100644 index 34ddc5a..0000000 --- a/images/frames/chat-projects.svg +++ /dev/null @@ -1,56 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Chat projects folder in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="67" y="57" width="826" height="446" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="70" y="60" width="820" height="440" rx="13" fill="#FAF8F4"/> - <rect x="70" y="60" width="820" height="440" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="72" y="62" width="816" height="436" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="70" y="60" width="820" height="36" rx="13" fill="#F3F0EA"/> - <rect x="70" y="84" width="820" height="12" fill="#F3F0EA"/> - <path d="M70 96 H890" stroke="#211F1C" stroke-width="1"/> - <path d="M70 97 H890" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="88" cy="78" r="5" fill="#C4B8A8"/> - <circle cx="104" cy="78" r="5" fill="#C4B8A8"/> - <circle cx="120" cy="78" r="5" fill="#1F4945"/> - - <text x="480.0" y="83" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Chat · Projects</text> - - <rect x="82" y="108" width="220" height="380" fill="#F3F0EA"/> - <text x="98" y="136" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#211F1C">Projects</text> - <rect x="94" y="152" width="196" height="36" rx="8" fill="#E1E5DE"/> - <rect x="94" y="152" width="3" height="36" fill="#1F4945"/> - <text x="110" y="175" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#1F4945">Launch notes</text> - <text x="110" y="220" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Research brief</text> - <text x="110" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Image drafts</text> - <text x="330" y="136" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Launch notes</text> - <text x="330" y="160" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Threads and Library files stay in this folder.</text> - <rect x="330" y="180" width="260" height="88" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="346" y="208" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#6E6A62">Thread</text> - <text x="346" y="232" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Outline the September launch</text> - <rect x="606" y="180" width="260" height="88" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="622" y="208" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#6E6A62">Library</text> - <text x="622" y="232" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">brief.pdf · pinned</text> - <rect x="330" y="284" width="536" height="160" rx="10" fill="#F3F0EA"/> - <text x="350" y="318" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">A project is a folder plus its chats —</text> - <text x="350" y="342" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">not a second selected pill in the sidebar.</text> - <text x="350" y="378" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Memory is account-scoped. Design canvases are a different object.</text> - -</svg> diff --git a/images/frames/chat-research.svg b/images/frames/chat-research.svg deleted file mode 100644 index 2627707..0000000 --- a/images/frames/chat-research.svg +++ /dev/null @@ -1,56 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Deep Research plan in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="77" y="53" width="806" height="454" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="80" y="56" width="800" height="448" rx="13" fill="#FAF8F4"/> - <rect x="80" y="56" width="800" height="448" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="82" y="58" width="796" height="444" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="80" y="56" width="800" height="36" rx="13" fill="#F3F0EA"/> - <rect x="80" y="80" width="800" height="12" fill="#F3F0EA"/> - <path d="M80 92 H880" stroke="#211F1C" stroke-width="1"/> - <path d="M80 93 H880" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="98" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="114" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="130" cy="74" r="5" fill="#1F4945"/> - - <text x="480.0" y="79" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Chat · Deep Research</text> - - <text x="100" y="124" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Stay in Chat · plan, then run</text> - <rect x="92" y="140" width="776" height="120" rx="10" fill="#F3F0EA"/> - <text x="112" y="172" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#211F1C">Research plan</text> - <text x="112" y="198" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">1. What shipped in Cortex Chat this month?</text> - <text x="112" y="222" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">2. Which sources should we trust?</text> - <rect x="748" y="160" width="96" height="32" rx="8" fill="#211F1C"/> - <text x="796" y="181" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#FAF8F4">Start</text> - <rect x="92" y="276" width="240" height="180" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="108" y="304" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Questions</text> - <text x="108" y="332" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="18" font-weight="600" fill="#211F1C">Up to 32</text> - <text x="108" y="360" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">8 in parallel</text> - <rect x="348" y="276" width="240" height="180" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="364" y="304" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Sources</text> - <text x="364" y="332" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="18" font-weight="600" fill="#211F1C">Up to 80</text> - <text x="364" y="360" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">4 fetches each</text> - <rect x="604" y="276" width="264" height="180" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="620" y="304" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Not a Code tool</text> - <text x="620" y="332" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="18" font-weight="600" fill="#211F1C">Chat turn only</text> - <text x="620" y="360" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Code refuses research.</text> - -</svg> diff --git a/images/frames/cli-terminal.svg b/images/frames/cli-terminal.svg deleted file mode 100644 index eb919bc..0000000 --- a/images/frames/cli-terminal.svg +++ /dev/null @@ -1,47 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Cortex CLI terminal frame"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="77" y="53" width="806" height="454" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="80" y="56" width="800" height="448" rx="13" fill="#161412"/> - <rect x="80" y="56" width="800" height="448" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="82" y="58" width="796" height="444" rx="11" fill="none" stroke="#3A3A3A" stroke-width="1"/> - <rect x="80" y="56" width="800" height="36" rx="13" fill="#1A1815"/> - <rect x="80" y="80" width="800" height="12" fill="#1A1815"/> - <path d="M80 92 H880" stroke="#3A3A3A" stroke-width="1"/> - <path d="M80 93 H880" stroke="#2A2824" stroke-width="1"/> - - <circle cx="98" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="114" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="130" cy="74" r="5" fill="#1F4945"/> - - <text x="480.0" y="79" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#FAF8F4">cortex — Cortex CLI — 120×40</text> - - <text x="100" y="132" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="14" font-weight="500" fill="#FAF8F4">Welcome to Cortex, the coding agent CLI</text> - <text x="100" y="160" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#B0AAA0">v0.1 · / commands · Enter to send</text> - <path d="M92 400 H868" stroke="#3A3A3A"/> - <path d="M92 402 H868" stroke="#2A2824"/> - <text x="100" y="434" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="13" font-weight="500" fill="#FAF8F4">> add a /healthz endpoint and cover it with a test</text> - <rect x="100" y="422" width="8" height="16" fill="#1F4945"/> - <path d="M92 456 H868" stroke="#3A3A3A"/> - <path d="M92 458 H868" stroke="#2A2824"/> - <text x="100" y="480" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" font-weight="500" fill="#B0AAA0">Cortex Mini 1</text> - <text x="860" y="480" text-anchor="end" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" fill="#B0AAA0">? help</text> - -</svg> diff --git a/images/frames/code-cloud.svg b/images/frames/code-cloud.svg deleted file mode 100644 index af997ea..0000000 --- a/images/frames/code-cloud.svg +++ /dev/null @@ -1,51 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Code Cloud guest in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="87" y="67" width="786" height="426" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="#FAF8F4"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="92" y="72" width="776" height="416" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="90" y="70" width="780" height="36" rx="13" fill="#F3F0EA"/> - <rect x="90" y="94" width="780" height="12" fill="#F3F0EA"/> - <path d="M90 106 H870" stroke="#211F1C" stroke-width="1"/> - <path d="M90 107 H870" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="108" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="124" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="140" cy="88" r="5" fill="#1F4945"/> - - <text x="480.0" y="93" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Code · Cloud guest</text> - - <rect x="102" y="118" width="368.0" height="360" rx="10" fill="#F3F0EA"/> - <text x="122" y="158" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Cloud guest</text> - <text x="122" y="190" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Isolated Firecracker machine</text> - <text x="122" y="230" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">read_file write_file edit_file</text> - <text x="122" y="258" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">glob grep bash todos</text> - <text x="122" y="298" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Headless — no desktop</text> - <text x="122" y="326" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Not Chat’s Python sandbox</text> - <rect x="490.0" y="118" width="368.0" height="360" rx="10" fill="#161412"/> - <text x="512.0" y="166" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#8AC5B9">prepare repository</text> - <text x="512.0" y="194" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#FAF8F4">attach guest</text> - <text x="512.0" y="222" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#FAF8F4">snapshot ready</text> - <text x="512.0" y="266" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#B0AAA0">This PC / SSH</text> - <text x="512.0" y="294" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#B0AAA0">desktop app and CLI only</text> - <text x="512.0" y="338" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="12" font-weight="500" fill="#B0AAA0">no Secrets page</text> - -</svg> diff --git a/images/frames/code-session.svg b/images/frames/code-session.svg deleted file mode 100644 index c1dc175..0000000 --- a/images/frames/code-session.svg +++ /dev/null @@ -1,51 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Code session timeline in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="67" y="53" width="826" height="454" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="70" y="56" width="820" height="448" rx="13" fill="#FAF8F4"/> - <rect x="70" y="56" width="820" height="448" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="72" y="58" width="816" height="444" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="70" y="56" width="820" height="36" rx="13" fill="#F3F0EA"/> - <rect x="70" y="80" width="820" height="12" fill="#F3F0EA"/> - <path d="M70 92 H890" stroke="#211F1C" stroke-width="1"/> - <path d="M70 93 H890" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="88" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="104" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="120" cy="74" r="5" fill="#1F4945"/> - - <text x="480.0" y="79" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Code · session</text> -<rect x="302" y="116" width="84" height="28" rx="8" fill="#FAF8F4" stroke="#E3DFD7"/><text x="344" y="135" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Ask</text><rect x="394" y="116" width="84" height="28" rx="8" fill="#FAF8F4" stroke="#E3DFD7"/><text x="436" y="135" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Plan</text><rect x="486" y="116" width="84" height="28" rx="8" fill="#E1E5DE" stroke="#E3DFD7"/><text x="528" y="135" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#1F4945">Agent</text> - <rect x="82" y="104" width="200" height="388" fill="#F3F0EA"/> - <text x="98" y="132" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Timeline</text> - <text x="98" y="160" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#211F1C">You · add /healthz + test</text> - <text x="98" y="188" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">read src/router.rs</text> - <text x="98" y="216" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#211F1C">edit src/router.rs</text> - <text x="98" y="244" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">bash cargo test</text> - <rect x="298" y="160" width="580" height="200" rx="10" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="318" y="192" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#211F1C">Agent can change the repository.</text> - <text x="318" y="220" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Ask and Plan do not edit files or run shell.</text> - <text x="318" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Stop cancels the live turn. A follow-up can pick</text> - <text x="318" y="276" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">a different mode. Web Code has no model picker.</text> - <rect x="298" y="376" width="580" height="88" rx="10" fill="#161412"/> - <text x="318" y="412" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="13" font-weight="500" fill="#FAF8F4">$ cargo test healthz</text> - <text x="318" y="436" text-anchor="start" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="13" font-weight="500" fill="#8AC5B9">ok healthz_returns_200</text> - -</svg> diff --git a/images/frames/design-canvas.svg b/images/frames/design-canvas.svg deleted file mode 100644 index 2fa4553..0000000 --- a/images/frames/design-canvas.svg +++ /dev/null @@ -1,55 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Design canvas with frames and library in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="67" y="53" width="826" height="454" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="70" y="56" width="820" height="448" rx="13" fill="#FAF8F4"/> - <rect x="70" y="56" width="820" height="448" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="72" y="58" width="816" height="444" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="70" y="56" width="820" height="36" rx="13" fill="#F3F0EA"/> - <rect x="70" y="80" width="820" height="12" fill="#F3F0EA"/> - <path d="M70 92 H890" stroke="#211F1C" stroke-width="1"/> - <path d="M70 93 H890" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="88" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="104" cy="74" r="5" fill="#C4B8A8"/> - <circle cx="120" cy="74" r="5" fill="#1F4945"/> - - <text x="480.0" y="79" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Design · Untitled canvas</text> - - <rect x="82" y="104" width="796" height="388" rx="8" fill="#F3F0EA"/> - <rect x="106" y="128" width="280" height="200" rx="8" fill="#FAF8F4" stroke="#211F1C" stroke-width="1.5"/> - <rect x="108" y="130" width="276" height="196" rx="6" fill="none" stroke="#1F4945" stroke-width="2"/> - <text x="122" y="160" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Frame 01</text> - <rect x="122" y="176" width="160" height="28" rx="6" fill="#211F1C"/> - <text x="202" y="195" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#FAF8F4">Primary</text> - <rect x="122" y="216" width="200" height="12" rx="2" fill="#E3DFD7"/> - <rect x="122" y="236" width="168" height="12" rx="2" fill="#E3DFD7"/> - <rect x="410" y="152" width="220" height="140" rx="8" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="426" y="184" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#6E6A62">Note</text> - <text x="426" y="212" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Hosted from Chat or Code.</text> - <text x="426" y="236" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Not a markdown sidecar.</text> - <rect x="678" y="104" width="200" height="388" fill="#FAF8F4" stroke="#E3DFD7"/> - <text x="694" y="140" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#211F1C">Library</text> - <text x="694" y="172" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Components</text> - <text x="694" y="196" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Pages</text> - <text x="694" y="220" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Tokens</text> - <text x="106" y="468" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Working UI is the Design desktop app.</text> - -</svg> diff --git a/images/frames/desktop.svg b/images/frames/desktop.svg deleted file mode 100644 index 422405c..0000000 --- a/images/frames/desktop.svg +++ /dev/null @@ -1,50 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Cortex desktop surfaces in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="97" y="77" width="766" height="406" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="100" y="80" width="760" height="400" rx="13" fill="#FAF8F4"/> - <rect x="100" y="80" width="760" height="400" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="102" y="82" width="756" height="396" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="100" y="80" width="760" height="36" rx="13" fill="#F3F0EA"/> - <rect x="100" y="104" width="760" height="12" fill="#F3F0EA"/> - <path d="M100 116 H860" stroke="#211F1C" stroke-width="1"/> - <path d="M100 117 H860" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="118" cy="98" r="5" fill="#C4B8A8"/> - <circle cx="134" cy="98" r="5" fill="#C4B8A8"/> - <circle cx="150" cy="98" r="5" fill="#1F4945"/> - - <text x="480.0" y="103" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex Desktop</text> - - <text x="124" y="156" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#6E6A62">This PC · SSH · Design</text> - <rect x="112" y="176" width="230" height="240" rx="10" fill="#F3F0EA" stroke="#E3DFD7"/> - <text x="132" y="212" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="15" font-weight="600" fill="#211F1C">This PC</text> - <text x="132" y="240" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Paired host for Code</text> - <text x="132" y="264" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">and Bot. Not in the browser.</text> - <rect x="362" y="176" width="230" height="240" rx="10" fill="#F3F0EA" stroke="#E3DFD7"/> - <text x="382" y="212" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="15" font-weight="600" fill="#211F1C">SSH</text> - <text x="382" y="240" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">A registered host.</text> - <text x="382" y="264" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Shell only, no desktop.</text> - <rect x="612" y="176" width="236" height="240" rx="10" fill="#F3F0EA" stroke="#1F4945" stroke-width="2"/> - <text x="632" y="212" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="15" font-weight="600" fill="#1F4945">Design</text> - <text x="632" y="240" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Working UI lives here.</text> - <text x="632" y="264" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">No /design web mode.</text> - -</svg> diff --git a/images/frames/github.svg b/images/frames/github.svg deleted file mode 100644 index be70f61..0000000 --- a/images/frames/github.svg +++ /dev/null @@ -1,46 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Connect GitHub control in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="97" y="77" width="766" height="406" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="100" y="80" width="760" height="400" rx="13" fill="#FAF8F4"/> - <rect x="100" y="80" width="760" height="400" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="102" y="82" width="756" height="396" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="100" y="80" width="760" height="36" rx="13" fill="#F3F0EA"/> - <rect x="100" y="104" width="760" height="12" fill="#F3F0EA"/> - <path d="M100 116 H860" stroke="#211F1C" stroke-width="1"/> - <path d="M100 117 H860" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="118" cy="98" r="5" fill="#C4B8A8"/> - <circle cx="134" cy="98" r="5" fill="#C4B8A8"/> - <circle cx="150" cy="98" r="5" fill="#1F4945"/> - - <text x="480.0" y="103" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Code · Connect GitHub</text> - - <text x="132" y="168" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="20" font-weight="600" fill="#211F1C">Connect GitHub</text> - <text x="132" y="204" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Code Home · repository picker · Settings → Integrations</text> - <rect x="132" y="238" width="280" height="48" rx="10" fill="#211F1C"/> - <text x="272" y="268" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#FAF8F4">Connect GitHub</text> - <rect x="432" y="238" width="200" height="48" rx="10" fill="#F3F0EA" stroke="#E3DFD7"/> - <text x="532" y="268" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="600" fill="#211F1C">Reconnect</text> - <text x="132" y="328" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#211F1C">There is no personal-access-token field.</text> - <text x="132" y="356" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#6E6A62">If GitHub is unavailable on this deployment,</text> - <text x="132" y="384" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#6E6A62">the product draws no Connect control.</text> - -</svg> diff --git a/images/frames/security.svg b/images/frames/security.svg deleted file mode 100644 index 17cebb8..0000000 --- a/images/frames/security.svg +++ /dev/null @@ -1,54 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Three Cortex sandboxes in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="77" y="61" width="806" height="438" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="80" y="64" width="800" height="432" rx="13" fill="#FAF8F4"/> - <rect x="80" y="64" width="800" height="432" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="82" y="66" width="796" height="428" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="80" y="64" width="800" height="36" rx="13" fill="#F3F0EA"/> - <rect x="80" y="88" width="800" height="12" fill="#F3F0EA"/> - <path d="M80 100 H880" stroke="#211F1C" stroke-width="1"/> - <path d="M80 101 H880" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="98" cy="82" r="5" fill="#C4B8A8"/> - <circle cx="114" cy="82" r="5" fill="#C4B8A8"/> - <circle cx="130" cy="82" r="5" fill="#1F4945"/> - - <text x="480.0" y="87" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Where code runs</text> - - <rect x="108" y="148" width="232" height="220" rx="12" fill="#F3F0EA" stroke="#E3DFD7"/> - <rect x="108" y="148" width="232" height="6" rx="3" fill="#1F4945"/> - <text x="124" y="192" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Chat Python</text> - <text x="124" y="228" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Small snippet sandbox.</text> - <text x="124" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">No workspace.</text> - - <rect x="358" y="148" width="232" height="220" rx="12" fill="#F3F0EA" stroke="#E3DFD7"/> - <rect x="358" y="148" width="232" height="6" rx="3" fill="#1F4945"/> - <text x="374" y="192" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Code Cloud</text> - <text x="374" y="228" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Isolated guest.</text> - <text x="374" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Headless.</text> - - <rect x="608" y="148" width="232" height="220" rx="12" fill="#F3F0EA" stroke="#E3DFD7"/> - <rect x="608" y="148" width="232" height="6" rx="3" fill="#1F4945"/> - <text x="624" y="192" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="16" font-weight="600" fill="#211F1C">Bot computer</text> - <text x="624" y="228" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Isolated guest.</text> - <text x="624" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#6E6A62">Desktop + shell.</text> -<text x="108" y="412" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Do not mix them. Chat Python cannot see a Code repository.</text> -</svg> diff --git a/images/frames/switcher.svg b/images/frames/switcher.svg deleted file mode 100644 index bdb4768..0000000 --- a/images/frames/switcher.svg +++ /dev/null @@ -1,57 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="960" height="560" viewBox="0 0 960 560" fill="none" role="img" aria-label="Cortex product switcher in a macOS window"> - - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="#FAF8F4" stop-opacity="0.35"/> - <stop offset="1" stop-color="#1F4945" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="960" height="560" fill="url(#sky)"/> - <rect width="960" height="560" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 560 L0 560 Z" fill="#1F4945" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 560 L0 560 Z" fill="#211F1C" opacity="0.16"/> - <ellipse cx="80" cy="430" rx="90" ry="64" fill="#1F4945" opacity="0.18"/><ellipse cx="180" cy="410" rx="70" ry="50" fill="#1F4945" opacity="0.22"/><ellipse cx="300" cy="440" rx="110" ry="79" fill="#1F4945" opacity="0.26"/><ellipse cx="720" cy="420" rx="95" ry="68" fill="#1F4945" opacity="0.18"/><ellipse cx="860" cy="400" rx="80" ry="57" fill="#1F4945" opacity="0.22"/> - - - <rect x="87" y="67" width="786" height="426" rx="16" fill="none" stroke="#1F4945" stroke-width="2"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="#FAF8F4"/> - <rect x="90" y="70" width="780" height="420" rx="13" fill="none" stroke="#211F1C" stroke-width="1.5"/> - <rect x="92" y="72" width="776" height="416" rx="11" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <rect x="90" y="70" width="780" height="36" rx="13" fill="#F3F0EA"/> - <rect x="90" y="94" width="780" height="12" fill="#F3F0EA"/> - <path d="M90 106 H870" stroke="#211F1C" stroke-width="1"/> - <path d="M90 107 H870" stroke="#E3DFD7" stroke-width="1"/> - - <circle cx="108" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="124" cy="88" r="5" fill="#C4B8A8"/> - <circle cx="140" cy="88" r="5" fill="#1F4945"/> - - <text x="480.0" y="93" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">Cortex — cortex.foundation</text> - - <rect x="102" y="118" width="168" height="360" fill="#F3F0EA"/> - <path d="M270 118 V478" stroke="#E3DFD7" stroke-width="1"/> - <text x="118" y="146" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#211F1C">New chat</text> - <text x="118" y="174" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#6E6A62">Projects</text> - <rect x="112" y="186" width="148" height="28" rx="7" fill="#E1E5DE"/> - <text x="124" y="205" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="#1F4945">Launch notes</text> - <text x="124" y="236" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Research brief</text> - <text x="124" y="264" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="500" fill="#6E6A62">Image drafts</text> -<rect x="302" y="126" width="72" height="28" rx="7" fill="#E1E5DE"/><rect x="302" y="126" width="3" height="28" rx="1.5" fill="#1F4945"/><text x="338" y="145" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#1F4945">Chat</text><rect x="390" y="126" width="72" height="28" rx="7" fill="transparent"/><text x="426" y="145" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#6E6A62">Code</text><rect x="478" y="126" width="72" height="28" rx="7" fill="transparent"/><text x="514" y="145" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="600" fill="#6E6A62">Bot</text> - <rect x="302" y="170" width="280" height="44" rx="12" fill="#F3F0EA"/> - <text x="318" y="197" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">What can Cortex Chat do?</text> - <rect x="302" y="226" width="420" height="68" rx="12" fill="#FAF8F4" stroke="#E3DFD7" stroke-width="1"/> - <text x="318" y="252" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">Projects, documents, research, and pictures —</text> - <text x="318" y="274" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="13" font-weight="500" fill="#211F1C">before you sign in. Code and Bot need an account.</text> - - <rect x="302" y="406" width="532" height="56" rx="12" fill="#F3F0EA" stroke="#211F1C" stroke-width="1"/> - <rect x="304" y="408" width="528" height="52" rx="10" fill="none" stroke="#E3DFD7" stroke-width="1"/> - <text x="322" y="440" text-anchor="start" font-family="Inter, ui-sans-serif, sans-serif" font-size="14" font-weight="500" fill="#6E6A62">Ask Cortex anything…</text> - <rect x="788" y="420" width="46" height="28" rx="8" fill="#211F1C"/> - <text x="811" y="439" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="11" font-weight="600" fill="#FAF8F4">Send</text> - -</svg> diff --git a/images/icon-api.svg b/images/icon-api.svg deleted file mode 100644 index e3030c0..0000000 --- a/images/icon-api.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E4E0D6"/> - - <rect x="90" y="48" width="140" height="88" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <path d="M112 76h96M112 96h72M112 116h48" stroke="#1F4945" stroke-width="3" stroke-linecap="round"/> - -</svg> diff --git a/images/icon-bot.svg b/images/icon-bot.svg deleted file mode 100644 index e8e92bd..0000000 --- a/images/icon-bot.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#F0E6B0"/> - - <rect x="108" y="48" width="104" height="92" rx="28" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M160 48V34" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="160" cy="30" r="6" fill="#1F4945" stroke="#1C1917" stroke-width="1.6"/> - <circle cx="136" cy="88" r="7" fill="#1C1917"/> - <circle cx="184" cy="88" r="7" fill="#1C1917"/> - <path d="M140 114c8 10 32 10 40 0" fill="none" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <circle cx="214" cy="78" r="16" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <circle cx="214" cy="78" r="6" fill="#1F4945"/> - <path d="M214 62v6M214 88v6M198 78h6M224 78h6M203 67l4 4M221 85l4 4M203 89l4-4M221 71l4-4" stroke="#1F4945" stroke-width="1.6" stroke-linecap="round"/> - -</svg> diff --git a/images/icon-changelog.svg b/images/icon-changelog.svg deleted file mode 100644 index 0ce708d..0000000 --- a/images/icon-changelog.svg +++ /dev/null @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#EFE8DC"/> - - <rect x="70" y="44" width="100" height="108" rx="6" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M86 44v108M70 64h100M70 80h100M70 96h100" stroke="#1C1917" stroke-width="1.3" opacity="0.7"/> - <circle cx="78" cy="56" r="4" fill="#1F4945"/> - <circle cx="78" cy="72" r="4" fill="#1F4945"/> - <circle cx="78" cy="88" r="4" fill="#1F4945"/> - <path d="M196 120v-52" stroke="#1C1917" stroke-width="2.4" stroke-linecap="round"/> - <path d="M180 86l16-18 16 18" fill="none" stroke="#1F4945" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M236 128v-40" stroke="#1C1917" stroke-width="2.2" stroke-linecap="round"/> - <path d="M224 104l12-14 12 14" fill="none" stroke="#1F4945" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/> - -</svg> diff --git a/images/icon-chat.svg b/images/icon-chat.svg deleted file mode 100644 index 20ad0eb..0000000 --- a/images/icon-chat.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D2DC"/> - - <path d="M92 52h72c8 0 14 6 14 14v36c0 8-6 14-14 14H132l-16 16v-16H92c-8 0-14-6-14-14V66c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M52 40h78c8 0 14 6 14 14v34c0 8-6 14-14 14H92l-14 14v-14H52c-8 0-14-6-14-14V54c0-8 6-14 14-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M78 68c8-12 18-14 22-4-8 2-12 10-14 18-6-4-8-8-8-14z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M84 72c2 4 5 8 7 12" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/icon-cli.svg b/images/icon-cli.svg deleted file mode 100644 index 4b6d201..0000000 --- a/images/icon-cli.svg +++ /dev/null @@ -1,7 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E4E0D6"/> - - <rect x="70" y="40" width="180" height="108" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <text x="92" y="108" font-family="JetBrains Mono, ui-monospace, monospace" font-size="28" fill="#1F4945">>_</text> - -</svg> diff --git a/images/icon-code.svg b/images/icon-code.svg deleted file mode 100644 index 7109261..0000000 --- a/images/icon-code.svg +++ /dev/null @@ -1,13 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E8CDB8"/> - - <rect x="70" y="42" width="180" height="108" rx="10" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <circle cx="88" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="102" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <circle cx="116" cy="60" r="4" fill="#1C1917" opacity="0.35"/> - <path d="M78 72h164" stroke="#1C1917" stroke-width="1.6"/> - <path d="M128 92l-22 22 22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <path d="M192 92l22 22-22 22" fill="none" stroke="#1C1917" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/> - <rect x="156" y="88" width="8" height="52" rx="2" fill="#1F4945"/> - -</svg> diff --git a/images/icon-design.svg b/images/icon-design.svg deleted file mode 100644 index e87c3de..0000000 --- a/images/icon-design.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#C9D6C6"/> - - <rect x="96" y="36" width="128" height="108" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <path d="M168 58l28 72-18-6-10-66z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2" stroke-linejoin="round"/> - <path d="M168 58l-8 8 10 66" stroke="#1C1917" stroke-width="1.4"/> - <rect x="166" y="52" width="12" height="10" rx="1" fill="#1F4945" stroke="#1C1917" stroke-width="1.2"/> - <path d="M124 92c12-20 26-24 32-8-14 4-20 18-24 32-8-8-12-16-8-24z" fill="#1F4945" stroke="#1C1917" stroke-width="1.3"/> - <path d="M132 96c4 6 8 14 10 20" stroke="#1C1917" stroke-width="1.1" fill="none"/> - -</svg> diff --git a/images/icon-desktop.svg b/images/icon-desktop.svg deleted file mode 100644 index 8de1fff..0000000 --- a/images/icon-desktop.svg +++ /dev/null @@ -1,9 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#E4E0D6"/> - - <rect x="70" y="36" width="180" height="110" rx="8" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2"/> - <rect x="70" y="36" width="180" height="18" fill="#1F4945" opacity="0.2"/> - <rect x="148" y="150" width="24" height="10" fill="#1C1917"/> - <rect x="120" y="160" width="80" height="6" rx="2" fill="#1C1917"/> - -</svg> diff --git a/images/icon-getting-started.svg b/images/icon-getting-started.svg deleted file mode 100644 index d128f7b..0000000 --- a/images/icon-getting-started.svg +++ /dev/null @@ -1,17 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#D7E6D4"/> - - <!-- book --> - <path d="M86 46c18 6 34 6 52 0v78c-18 8-36 8-52 0V46z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M86 46c-18 6-34 6-52 0v78c18 8 36 8 52 0V46z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <path d="M86 46v78" stroke="#1C1917" stroke-width="2"/> - <!-- leaf --> - <path d="M54 88c10-18 22-22 28-8-12 4-18 16-22 28-8-8-10-14-6-20z" fill="#1F4945" stroke="#1C1917" stroke-width="1.4"/> - <path d="M62 92c4 6 8 12 10 18" stroke="#1C1917" stroke-width="1.2" fill="none"/> - <!-- compass --> - <circle cx="112" cy="96" r="18" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <circle cx="112" cy="96" r="3" fill="#1F4945"/> - <path d="M112 82v6M112 104v6M98 96h6M120 96h6" stroke="#1C1917" stroke-width="1.4"/> - <path d="M112 96 L104 108 L112 90 L120 108 Z" fill="#1F4945" opacity="0.85"/> - -</svg> diff --git a/images/icon-security.svg b/images/icon-security.svg deleted file mode 100644 index 1027d17..0000000 --- a/images/icon-security.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" fill="none" role="img"> - <rect width="320" height="180" rx="16" fill="#D5CEE0"/> - - <path d="M160 36c28 10 52 12 64 14v52c0 28-28 48-64 62-36-14-64-34-64-62V50c12-2 36-4 64-14z" fill="#FAF8F4" stroke="#1C1917" stroke-width="2.2" stroke-linejoin="round"/> - <rect x="142" y="88" width="36" height="28" rx="4" fill="#FAF8F4" stroke="#1C1917" stroke-width="2"/> - <path d="M150 88v-10a10 10 0 0 1 20 0v10" fill="none" stroke="#1C1917" stroke-width="2" stroke-linecap="round"/> - <circle cx="160" cy="102" r="3" fill="#1F4945"/> - <path d="M96 70c18-22 36-10 28 8-16 4-22 22-18 36 8-22-4-28-10-44z" fill="#1F4945" opacity="0.9" stroke="#1C1917" stroke-width="1.2"/> - <path d="M224 68c-18-20-36-8-28 10 16 4 22 20 18 34-8-20 4-26 10-44z" fill="#1F4945" opacity="0.9" stroke="#1C1917" stroke-width="1.2"/> - -</svg> diff --git a/images/product/README.md b/images/product/README.md deleted file mode 100644 index 206cfcf..0000000 --- a/images/product/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Product screenshots - -Live Cortex app captures (1280×800, guest session unless noted) taken from -`cortex.foundation` with headless Chrome. These are the product heroes. Do -not replace them with SVG mocks or marked placeholders, and do not reuse one -capture on more than one page — every guide shows a distinct surface. - -Cream / ink / `#1F4945` stay on site chrome. The pixels are the app. - -## Chat - -| File | Surface | Used on | -| --- | --- | --- | -| `chat-home.png` | Chat home, empty guest session | `getting-started/quickstart` | -| `chat-home-recents.png` | Chat home with Recents populated | `index` | -| `chat-home-dark.png` | Chat home, Dark theme | `chat/index` | -| `chat-home-fr.png` | Chat home, French interface | `getting-started/what-is-cortex` | -| `chat-session.png` | A thread with a one-paragraph reply | `chat/index` | -| `chat-composer-typed.png` | A multi-line prompt typed in the composer | `chat/quickstart` | -| `chat-composer-menu.png` | The composer `+` menu: Attach file, Image, Check origin | `chat/images` | -| `chat-model-picker.png` | Model chip open: models, Thinking, Deep Research | `chat/models` | -| `chat-deep-research.png` | Research card prefill with Deep Research on | `chat/deep-research` | -| `chat-streaming.png` | A turn in flight — “Cortex is responding…” | `chat/streaming` | -| `chat-reply-headings.png` | A finished reply with headings | `chat/how-it-works` | -| `chat-reply-code.png` | A reply with a Python code block, Copy and Listen | `chat/voice` | -| `chat-canvas-document.png` | A new chat with a document canvas open | `chat/canvases` | -| `chat-projects.png` | Projects, empty state | `chat/projects` | -| `chat-new-project.png` | New project dialog | `chat/projects` | -| `chat-move-to-project.png` | Move to project popover on a thread | `chat/projects` | -| `chat-library.png` | Library, empty state with type filters | `chat/library` | -| `chat-planning.png` | Planning, empty state with filters | `chat/plans` | -| `chat-start-plan.png` | Start a plan from this chat | `chat/plans` | -| `chat-new-plan.png` | New plan dialog | `chat/plans` | -| `chat-connectors.png` | Customize → Connectors | `chat/tools` | - -## Settings and account - -| File | Surface | Used on | -| --- | --- | --- | -| `accounts-sign-in.png` | The sign-in dialog | `getting-started/accounts` | -| `settings-general.png` | Settings → General | `getting-started/settings` | -| `settings-shortcuts.png` | Settings → General, keyboard shortcuts | `getting-started/settings` | -| `settings-models.png` | Settings → Models | `chat/models` | -| `settings-integrations.png` | Settings → Integrations, Connect GitHub | `code/github` | -| `settings-mcp-servers.png` | Settings → Integrations, MCP servers | `chat/tools` | -| `settings-data-privacy.png` | Settings → Data & privacy, top | `security/overview` | -| `settings-memory.png` | Settings → Data & privacy, Memory and Your data | `chat/memory` | -| `settings-plans.png` | Settings → Plan & billing, plan cards | `getting-started/plans` | -| `settings-plan-usage.png` | Settings → Plan & billing, guest usage | `getting-started/plans` | -| `privacy-cookie-banner.png` | Cookie consent banner on first visit | `security/overview` | - -## Code, Bot, Security, Foundation - -| File | Surface | Used on | -| --- | --- | --- | -| `code-public.png` | `cortex.foundation/code` public page | `code/index` | -| `code-public-features.png` | Same page, feature grid | `code/index` | -| `code-home.png` | Code guest gate (“This space is reserved”) | `code/quickstart` | -| `bot-public.png` | `cortex.foundation/bot` public page | `bot/index` | -| `bot-public-features.png` | Same page, feature grid | `bot/index` | -| `bot-home.png` | Bot guest gate | `bot/quickstart` | -| `security-public.png` | `cortex.foundation/security` public page | `code/security` | -| `security-public-features.png` | Same page, feature grid | `code/security` | -| `news-announcement.png` | News: Chat, Code, and Bot are live | `changelog` | -| `about.png` | `cortex.foundation/about` | `getting-started/what-is-cortex` | - -## Not yet captured - -Member-only surfaces have no guest capture and their pages ship without a -product frame until one lands: a Code session timeline in the web app, the -Bot setup form and Computer rail, a Design canvas in the desktop app, the -Bot desktop app. Capture them from a signed-in staging account at 1280×800 -and add a row above; never substitute an SVG mock. - -CLI stills live in `images/cli/` (vendored from CortexLM/cli). diff --git a/images/product/about.png b/images/product/about.png deleted file mode 100644 index 063775c..0000000 Binary files a/images/product/about.png and /dev/null differ diff --git a/images/product/accounts-sign-in.png b/images/product/accounts-sign-in.png deleted file mode 100644 index 92c051d..0000000 Binary files a/images/product/accounts-sign-in.png and /dev/null differ diff --git a/images/product/bot-home.png b/images/product/bot-home.png deleted file mode 100644 index 8f4618b..0000000 Binary files a/images/product/bot-home.png and /dev/null differ diff --git a/images/product/bot-public-features.png b/images/product/bot-public-features.png deleted file mode 100644 index 787bc7c..0000000 Binary files a/images/product/bot-public-features.png and /dev/null differ diff --git a/images/product/bot-public.png b/images/product/bot-public.png deleted file mode 100644 index 7a7f5fd..0000000 Binary files a/images/product/bot-public.png and /dev/null differ diff --git a/images/product/chat-canvas-document.png b/images/product/chat-canvas-document.png deleted file mode 100644 index 3af24a2..0000000 Binary files a/images/product/chat-canvas-document.png and /dev/null differ diff --git a/images/product/chat-composer-menu.png b/images/product/chat-composer-menu.png deleted file mode 100644 index 07e35d3..0000000 Binary files a/images/product/chat-composer-menu.png and /dev/null differ diff --git a/images/product/chat-composer-typed.png b/images/product/chat-composer-typed.png deleted file mode 100644 index 05cb2ad..0000000 Binary files a/images/product/chat-composer-typed.png and /dev/null differ diff --git a/images/product/chat-connectors.png b/images/product/chat-connectors.png deleted file mode 100644 index 44b7d04..0000000 Binary files a/images/product/chat-connectors.png and /dev/null differ diff --git a/images/product/chat-deep-research.png b/images/product/chat-deep-research.png deleted file mode 100644 index 232a093..0000000 Binary files a/images/product/chat-deep-research.png and /dev/null differ diff --git a/images/product/chat-home-dark.png b/images/product/chat-home-dark.png deleted file mode 100644 index e7c56ea..0000000 Binary files a/images/product/chat-home-dark.png and /dev/null differ diff --git a/images/product/chat-home-fr.png b/images/product/chat-home-fr.png deleted file mode 100644 index 8b7cef8..0000000 Binary files a/images/product/chat-home-fr.png and /dev/null differ diff --git a/images/product/chat-home-recents.png b/images/product/chat-home-recents.png deleted file mode 100644 index 2f51585..0000000 Binary files a/images/product/chat-home-recents.png and /dev/null differ diff --git a/images/product/chat-home.png b/images/product/chat-home.png deleted file mode 100644 index 36a2fb3..0000000 Binary files a/images/product/chat-home.png and /dev/null differ diff --git a/images/product/chat-library.png b/images/product/chat-library.png deleted file mode 100644 index 790bdeb..0000000 Binary files a/images/product/chat-library.png and /dev/null differ diff --git a/images/product/chat-model-picker.png b/images/product/chat-model-picker.png deleted file mode 100644 index feae973..0000000 Binary files a/images/product/chat-model-picker.png and /dev/null differ diff --git a/images/product/chat-move-to-project.png b/images/product/chat-move-to-project.png deleted file mode 100644 index 574f690..0000000 Binary files a/images/product/chat-move-to-project.png and /dev/null differ diff --git a/images/product/chat-new-plan.png b/images/product/chat-new-plan.png deleted file mode 100644 index d6294d1..0000000 Binary files a/images/product/chat-new-plan.png and /dev/null differ diff --git a/images/product/chat-new-project.png b/images/product/chat-new-project.png deleted file mode 100644 index b8d4c00..0000000 Binary files a/images/product/chat-new-project.png and /dev/null differ diff --git a/images/product/chat-planning.png b/images/product/chat-planning.png deleted file mode 100644 index c5fbd4a..0000000 Binary files a/images/product/chat-planning.png and /dev/null differ diff --git a/images/product/chat-projects.png b/images/product/chat-projects.png deleted file mode 100644 index cc0b311..0000000 Binary files a/images/product/chat-projects.png and /dev/null differ diff --git a/images/product/chat-reply-code.png b/images/product/chat-reply-code.png deleted file mode 100644 index 173b209..0000000 Binary files a/images/product/chat-reply-code.png and /dev/null differ diff --git a/images/product/chat-reply-headings.png b/images/product/chat-reply-headings.png deleted file mode 100644 index 83a7b27..0000000 Binary files a/images/product/chat-reply-headings.png and /dev/null differ diff --git a/images/product/chat-session.png b/images/product/chat-session.png deleted file mode 100644 index 833fd6f..0000000 Binary files a/images/product/chat-session.png and /dev/null differ diff --git a/images/product/chat-start-plan.png b/images/product/chat-start-plan.png deleted file mode 100644 index df9d9a9..0000000 Binary files a/images/product/chat-start-plan.png and /dev/null differ diff --git a/images/product/chat-streaming.png b/images/product/chat-streaming.png deleted file mode 100644 index acba363..0000000 Binary files a/images/product/chat-streaming.png and /dev/null differ diff --git a/images/product/code-home.png b/images/product/code-home.png deleted file mode 100644 index cf2508c..0000000 Binary files a/images/product/code-home.png and /dev/null differ diff --git a/images/product/code-public-features.png b/images/product/code-public-features.png deleted file mode 100644 index 173fe6e..0000000 Binary files a/images/product/code-public-features.png and /dev/null differ diff --git a/images/product/code-public.png b/images/product/code-public.png deleted file mode 100644 index c22fd5a..0000000 Binary files a/images/product/code-public.png and /dev/null differ diff --git a/images/product/news-announcement.png b/images/product/news-announcement.png deleted file mode 100644 index b51a342..0000000 Binary files a/images/product/news-announcement.png and /dev/null differ diff --git a/images/product/privacy-cookie-banner.png b/images/product/privacy-cookie-banner.png deleted file mode 100644 index 157f281..0000000 Binary files a/images/product/privacy-cookie-banner.png and /dev/null differ diff --git a/images/product/security-public-features.png b/images/product/security-public-features.png deleted file mode 100644 index 93401b5..0000000 Binary files a/images/product/security-public-features.png and /dev/null differ diff --git a/images/product/security-public.png b/images/product/security-public.png deleted file mode 100644 index 81e7983..0000000 Binary files a/images/product/security-public.png and /dev/null differ diff --git a/images/product/settings-data-privacy.png b/images/product/settings-data-privacy.png deleted file mode 100644 index eb27b14..0000000 Binary files a/images/product/settings-data-privacy.png and /dev/null differ diff --git a/images/product/settings-general.png b/images/product/settings-general.png deleted file mode 100644 index 984be56..0000000 Binary files a/images/product/settings-general.png and /dev/null differ diff --git a/images/product/settings-integrations.png b/images/product/settings-integrations.png deleted file mode 100644 index f0fb192..0000000 Binary files a/images/product/settings-integrations.png and /dev/null differ diff --git a/images/product/settings-mcp-servers.png b/images/product/settings-mcp-servers.png deleted file mode 100644 index 10fed8c..0000000 Binary files a/images/product/settings-mcp-servers.png and /dev/null differ diff --git a/images/product/settings-memory.png b/images/product/settings-memory.png deleted file mode 100644 index b7ac8d6..0000000 Binary files a/images/product/settings-memory.png and /dev/null differ diff --git a/images/product/settings-models.png b/images/product/settings-models.png deleted file mode 100644 index 91860d2..0000000 Binary files a/images/product/settings-models.png and /dev/null differ diff --git a/images/product/settings-plan-usage.png b/images/product/settings-plan-usage.png deleted file mode 100644 index d4455cf..0000000 Binary files a/images/product/settings-plan-usage.png and /dev/null differ diff --git a/images/product/settings-plans.png b/images/product/settings-plans.png deleted file mode 100644 index 11eced5..0000000 Binary files a/images/product/settings-plans.png and /dev/null differ diff --git a/images/product/settings-shortcuts.png b/images/product/settings-shortcuts.png deleted file mode 100644 index a82a11b..0000000 Binary files a/images/product/settings-shortcuts.png and /dev/null differ diff --git a/index.mdx b/index.mdx index a3e9c66..778c8ba 100644 --- a/index.mdx +++ b/index.mdx @@ -1,89 +1,130 @@ --- -title: "Guides for Chat, Code, Bot, Design, and the CLI" -description: "Product docs for the Cortex app — how to chat, ship code, run bots, design canvases, and drive Code from a terminal. Platform API lives elsewhere." -image: "/images/banners/getting-started.png" -keywords: ["Cortex docs", "documentation", "help", "guides"] +title: "Cortex documentation" +description: "Guides for every Cortex application: Chat, Code, Bot, the CLI, Design and Security, plus accounts, plans, settings and reference." +icon: "house" --- -<code>docs.cortex.foundation</code> +Cortex is a set of applications that share one account on `cortex.foundation`. **Cortex Chat** answers questions and does research, **Cortex Code** works inside your repositories, **Cortex Bot** runs on a computer of its own, **Cortex CLI** drives Code from a terminal, **Cortex Design** holds canvases, and **Cortex Security** reviews pull requests where they already live. The same sign-in opens all of them. -Product docs for the Cortex app — how to chat, ship code, run bots, design canvases, and drive Code from a terminal. One account, one domain. **Platform API lives elsewhere.** +This is the product documentation. It explains what each application does, what you can do without an account, what signing in adds, and where every control lives. Start with the card for the application you came here for, or take the quickstart if you have never opened Cortex at all. -<Frame caption="Cortex Chat home — Chat, Code, and Bot in the sidebar; recent conversations; the composer with its model chip; Code, Research, Docs, and Agents as starting points."> - <img src="/images/product/chat-home-recents.png" alt="Cortex Chat home with recent conversations in the sidebar and the composer ready" /> -</Frame> - -<p className="ink-cta-row"> - <a className="ink-btn" href="/getting-started/quickstart">Quickstart</a> - <a className="ink-btn ink-btn-quiet" href="/getting-started/downloads">Download Cortex</a> -</p> - -## Start here +## Pick an application <CardGroup cols={3}> - <Card title="Getting started" img="/images/banners/getting-started.png" href="/getting-started/quickstart"> - A first chat as a guest, then sign in for Code, Bot, and Design. Accounts, plans, settings. + <Card title="Cortex Chat" icon="comments" href="/chat/index"> + Ask, research and create. Conversations, projects, Library, memory, tools, images and scheduled tasks. The only application that works before you sign in. </Card> - <Card title="Chat" img="/images/banners/chat.png" href="/chat"> - Projects, Library, plans, models, tools, Deep Research, images, and how a turn runs. + <Card title="Cortex Code" icon="code" href="/code/index"> + Agents in your repositories. Sessions, isolated runtimes, approvals, changes, tickets and pull-request review. Not a chat with a different icon. </Card> - <Card title="Code" img="/images/banners/code.png" href="/code"> - A coding agent in an isolated Cloud guest — sessions, Ask / Plan / Agent, GitHub, review. + <Card title="Cortex Bot" icon="robot" href="/bot/index"> + A teammate with a computer. A bot browses, clicks and works on a desktop you can watch, and parks consequential steps for your approval. </Card> - <Card title="Bot" img="/images/banners/bot.png" href="/bot"> - Always-on agents with their own computer, approvals, routines, skills, and the Bot desktop app. + <Card title="Cortex CLI" icon="terminal" href="/cli/index"> + Cortex Code in the terminal. Install, sign in, run sessions, use local and remote hosts, script headless runs and wire it into continuous integration. </Card> - <Card title="Design" img="/images/banners/design.png" href="/design"> - Persistable canvases hosted from Chat or Code, edited in the Design desktop app. + <Card title="Cortex Design" icon="pen-ruler" href="/design/index"> + Canvases hosted from Chat or Code and edited in the Cortex Design desktop app. Versions, a reusable library and export. </Card> - <Card title="CLI" icon="terminal" href="/cli"> - Cortex Code in the terminal — install, sign in, the TUI, slash commands, `/goal`, headless runs. + <Card title="Cortex Security" icon="shield-halved" href="/security/index"> + Pull-request review without pasting a diff. The change stays in the repository and Cortex reads it there, then writes a check run and a summary. </Card> </CardGroup> -## Reference +## Which one do I need? -<CardGroup cols={3}> - <Card title="Troubleshooting" icon="life-buoy" href="/getting-started/troubleshooting"> - What a message means across Chat, Code, and Bot — gates, quotas, reconnects. +| You want to | Open | +| --- | --- | +| Ask a question, write, research, work with documents or pictures | [Cortex Chat](/chat/index) | +| Change a repository, run tests, open a pull request | [Cortex Code](/code/index) | +| Hand ongoing work to an agent that browses and clicks on its own desktop | [Cortex Bot](/bot/index) | +| Drive the same Code sessions from your terminal, a script or a pipeline | [Cortex CLI](/cli/index) | +| Lay out a board of frames, components and notes | [Cortex Design](/design/index) | +| Review changes in the repository where they already live | [Cortex Security](/security/index) | + +For the long version, with what each one needs before it will open, read [Which product do I need?](/getting-started/choose-a-product). + +<Note> +Chat is never gated. Everything else is for signed-in accounts, and Cortex Code and Cortex Bot are in closed beta, so a signed-in account that has not been invited sees a dialog offering to continue in Chat. See [Accounts and sign-in](/getting-started/accounts). +</Note> + +## First steps + +<CardGroup cols={2}> + <Card title="Quickstart" icon="rocket" href="/getting-started/quickstart"> + From an open browser tab to a first answer, then sign in and open the rest. </Card> - <Card title="Security and privacy" icon="shield-check" href="/security/overview"> - What Cortex stores, cookies and consent, where code runs, export and deletion. + <Card title="What is Cortex" icon="circle-info" href="/getting-started/what-is-cortex"> + The applications, the models, the one account, and which hostname serves what. </Card> - <Card title="API" icon="braces" href="/api/overview"> - The problem-document format and the public catalog of error codes. + <Card title="Which product do I need?" icon="signs-post" href="/getting-started/choose-a-product"> + A task table that maps what you want to do to the application that does it. </Card> - <Card title="System status" icon="activity" href="/status"> - Live availability for Web, API, Chat, Code, and Bot — incidents and maintenance. + <Card title="Accounts and sign-in" icon="user" href="/getting-started/accounts"> + What a guest can do, what signing in adds, and how the member-only gates read. </Card> - <Card title="Changelog" icon="history" href="/changelog"> - What shipped in Chat, Code, Bot, Design, and the CLI — dated, with the surface it changed. + <Card title="Plans and quotas" icon="credit-card" href="/getting-started/plans"> + Guest, Free, Go, Plus and Pro, the two message windows, and how a limit resets. </Card> - <Card title="Platform API" icon="clock" href="/platform"> - Not available yet. No endpoints, SDKs, or keys — and what to use instead. + <Card title="Ways to run Cortex" icon="download" href="/getting-started/downloads"> + The browser, the desktop app and the command line, and what only the last two can do. </Card> </CardGroup> -## Which product do I want? +## Settings and your data -| You want to… | Open | -| --- | --- | -| Ask questions, write, research with citations, work with documents and pictures | [Chat](/chat) | -| Change a repository, run tests, open a pull request | [Code](/code) | -| Delegate ongoing work to an agent that browses, clicks, and runs on a schedule | [Bot](/bot) | -| Drive Code from your own terminal, a script, or CI | [CLI](/cli) | -| Lay out frames, notes, and a component library on a board | [Design](/design) | +<CardGroup cols={2}> + <Card title="Settings" icon="gear" href="/getting-started/settings"> + The seven Settings tabs and every control inside them, plus the search across tabs. + </Card> + <Card title="Data and privacy" icon="user-shield" href="/getting-started/data-and-privacy"> + Cookie consent, Global Privacy Control, memory, export and permanent deletion. + </Card> + <Card title="Two-factor authentication" icon="lock" href="/getting-started/two-factor"> + Enrol an authenticator app, and the confirmation that export and deletion require. + </Card> + <Card title="Interface language" icon="language" href="/getting-started/language"> + The eight interface languages, how to switch, and what stays in English. + </Card> +</CardGroup> -Chat works before you sign in. Code, Bot, and Design need an account — see [Accounts](/getting-started/accounts). +## Reference and help -<Note> -The inference **Platform API** (a public model-inference API) is not documented on this site and is not implemented in this repository. See [Platform API](/platform). -</Note> +<CardGroup cols={3}> + <Card title="Troubleshooting" icon="life-ring" href="/getting-started/troubleshooting"> + What a message means across Chat, Code and Bot: gates, quotas, reconnects, maintenance. + </Card> + <Card title="Limits and quotas" icon="gauge-high" href="/reference/limits"> + Every user-facing limit in one table. + </Card> + <Card title="Models" icon="microchip" href="/reference/models"> + The models Cortex serves today and what each one is for. + </Card> + <Card title="Errors" icon="triangle-exclamation" href="/reference/errors"> + How a failure is reported, and the catalogue of problem codes behind it. + </Card> + <Card title="Problem catalog" icon="list" href="/problems/index"> + One page per problem code, with what it means and what to do. + </Card> + <Card title="Security and privacy" icon="user-shield" href="/reference/security-and-privacy"> + What Cortex stores, what it never stores, and what this deployment does not certify. + </Card> + <Card title="System status" icon="signal" href="/reference/status"> + Live availability, incidents and maintenance windows. + </Card> + <Card title="Cortex Bounty" icon="coins" href="/bounty/index"> + Pair a hotkey, file a report, and how verdicts are scored. + </Card> + <Card title="Changelog" icon="clock-rotate-left" href="/changelog"> + What shipped, dated, with the surface it changed. + </Card> +</CardGroup> -## Next +## Related -1. [Quickstart](/getting-started/quickstart) — a first Chat, then the surfaces that need an account. -2. [What is Cortex](/getting-started/what-is-cortex) — the products, the models, and the hostnames in one place. -3. [Accounts](/getting-started/accounts) — what a guest can do, and what signing in unlocks. -4. [Downloads](/getting-started/downloads) — the desktop apps and the CLI, when you need a host the browser cannot offer. -5. [Troubleshooting](/getting-started/troubleshooting) — when a message is not an error. +- [Quickstart](/getting-started/quickstart) +- [What is Cortex](/getting-started/what-is-cortex) +- [Which product do I need?](/getting-started/choose-a-product) +- [Frequently asked questions](/getting-started/faq) +- [Glossary](/getting-started/glossary) +- [Troubleshooting](/getting-started/troubleshooting) diff --git a/logo/banner-dark.png b/logo/banner-dark.png deleted file mode 100644 index 7fc5c9f..0000000 Binary files a/logo/banner-dark.png and /dev/null differ diff --git a/logo/banner-light.png b/logo/banner-light.png deleted file mode 100644 index 1fcf12c..0000000 Binary files a/logo/banner-light.png and /dev/null differ diff --git a/platform.mdx b/platform.mdx deleted file mode 100644 index 9d6fc34..0000000 --- a/platform.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Platform API" -description: "Coming soon. There is no public inference API to document yet — no endpoints, SDKs, or API keys." -keywords: ["inference API", "completions", "roadmap", "coming soon"] ---- - -Cortex does not have a public inference API today. There is no completions -endpoint, no SDK, and no API key to request. This page exists so the -navigation does not grow a reference for something that is not there. - -## What is available now - -| You want to… | Use | -| --- | --- | -| Ask questions, write, and research | [Cortex Chat](/chat) | -| Change a repository | [Cortex Code](/code) | -| Delegate ongoing work to an agent with a computer | [Cortex Bot](/bot) | -| Drive Code from a terminal, a script, or CI | [Cortex CLI](/cli) | -| Build a client against the app's error contract | [Public API](/api/overview) and the [problem catalog](/problems) | - -## What is not available - -- **Model inference as a service.** No endpoint takes a prompt and returns a - completion. -- **Platform API keys.** Metered inference keys are not issued, so there is - nothing to generate in Settings. -- **An SDK.** No client library wraps a Platform API. - -The [API tab](/api/overview) documents the RFC 9457 problem format the apps -and the CLI already use. That is the whole public API surface. - -## What to do instead - -Most requests that sound like an API call already have a product answer: - -| The API-shaped ask | What exists today | -| --- | --- | -| Run a prompt from a script | The [CLI](/cli) — `cortex run` for a one-shot, `cortex exec` for CI | -| Automate a repository change | A [Code session](/code), or `cortex exec` with a git diff | -| Put an agent on a schedule | A Bot [routine](/bot/routines) | -| React to an error your integration sees | Branch on `code` from the [problem catalog](/problems) | -| Connect an external tool to a chat | An [MCP server](/chat/tools) under **Settings → Integrations** | - -These are product surfaces with their own sign-in, not API keys. If you need -something none of them covers, that is a gap in the Platform API — not a -hidden endpoint. - -## When this changes - -A Platform API would be announced on the [changelog](/changelog) and at -[cortex.foundation](https://cortex.foundation) first. Until an announcement -exists, treat any page or tool claiming to sell Platform API access as -unofficial. - -## Related - -- [Public API](/api/overview) — what this site does document. -- [Problem catalog](/problems) — the `type` URIs every error points at. -- [CLI headless runs](/cli/headless) — the closest thing to an automation surface today. -- [Changelog](/changelog) — where a Platform launch would appear. diff --git a/problems/bad_request.mdx b/problems/bad_request.mdx index 258b020..e759bdd 100644 --- a/problems/bad_request.mdx +++ b/problems/bad_request.mdx @@ -24,6 +24,6 @@ Syntactically valid but semantically impossible — for example a cursor that de ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/concurrency_limit_reached.mdx b/problems/concurrency_limit_reached.mdx index efb0940..388015a 100644 --- a/problems/concurrency_limit_reached.mdx +++ b/problems/concurrency_limit_reached.mdx @@ -24,6 +24,6 @@ Too many concurrent agent runs for this plan. ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/conflict.mdx b/problems/conflict.mdx index d820e55..cd807c9 100644 --- a/problems/conflict.mdx +++ b/problems/conflict.mdx @@ -10,7 +10,7 @@ description: "Conflict. HTTP 409." | `type` | `https://docs.cortex.foundation/problems/conflict` | | Retryable | yes | -Optimistic concurrency or a uniqueness constraint lost a race. Retrying the identical request can succeed. +Optimistic concurrency or a uniqueness constraint lost a race. This is the one 4xx worth retrying, but not with the same body: reload to pick up the current version, then apply your change again. ```json { @@ -24,6 +24,6 @@ Optimistic concurrency or a uniqueness constraint lost a race. Retrying the iden ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/content_policy.mdx b/problems/content_policy.mdx index 0567de1..9234f91 100644 --- a/problems/content_policy.mdx +++ b/problems/content_policy.mdx @@ -24,6 +24,6 @@ Blocked by content policy. The request is outside what Cortex will help with. ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/entitlement_required.mdx b/problems/entitlement_required.mdx index 09cae36..2fcd8f3 100644 --- a/problems/entitlement_required.mdx +++ b/problems/entitlement_required.mdx @@ -24,6 +24,6 @@ Authenticated, but the plan does not include this capability at all — as oppos ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/forbidden.mdx b/problems/forbidden.mdx index 4b1d388..c7553e1 100644 --- a/problems/forbidden.mdx +++ b/problems/forbidden.mdx @@ -10,7 +10,7 @@ description: "Not permitted. HTTP 403." | `type` | `https://docs.cortex.foundation/problems/forbidden` | | Retryable | no | -Authenticated, but this principal may not perform this action. Distinct from a missing plan capability (`entitlement_required`). +Authenticated, but this account may not perform this action. Distinct from a missing plan capability (`entitlement_required`). ```json { @@ -24,6 +24,6 @@ Authenticated, but this principal may not perform this action. Distinct from a m ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/gone.mdx b/problems/gone.mdx index f8e671d..ec5f437 100644 --- a/problems/gone.mdx +++ b/problems/gone.mdx @@ -24,6 +24,6 @@ The resource existed and was deliberately destroyed. Distinct from `not_found` s ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/idempotency_key_reuse.mdx b/problems/idempotency_key_reuse.mdx index a2798a1..eb59e51 100644 --- a/problems/idempotency_key_reuse.mdx +++ b/problems/idempotency_key_reuse.mdx @@ -24,6 +24,6 @@ The `Idempotency-Key` header was reused with a different request body. Replay th ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/index.mdx b/problems/index.mdx index 6136bc7..bc06cf4 100644 --- a/problems/index.mdx +++ b/problems/index.mdx @@ -1,6 +1,7 @@ --- title: "Problem catalog" description: "Every Cortex error code, its HTTP status, whether retrying helps, and the page that explains it." +icon: "list" keywords: ["error codes", "troubleshooting", "status codes"] --- @@ -56,6 +57,6 @@ The base is `https://docs.cortex.foundation/problems`. Each code has a page at ` ## Related -- [Errors](/api/errors) — the shape of a problem document and which fields to render. -- [Public API](/api/overview) — what this tab covers. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - the shape of a problem document and which fields to render. +- [Platform API](/reference/platform-api) - why there is no public inference API to raise these codes against yet. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/internal.mdx b/problems/internal.mdx index 500c601..96883a8 100644 --- a/problems/internal.mdx +++ b/problems/internal.mdx @@ -24,6 +24,6 @@ Catch-all for our own bugs. Never carries `detail`. Quote `request_id` in a supp ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/invalid_credential.mdx b/problems/invalid_credential.mdx index 13899cd..dbe23b2 100644 --- a/problems/invalid_credential.mdx +++ b/problems/invalid_credential.mdx @@ -24,6 +24,6 @@ The sign-in was well-formed but is expired, revoked, or no longer valid. Sign in ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/invalid_state.mdx b/problems/invalid_state.mdx index 09b45ba..94c3fd5 100644 --- a/problems/invalid_state.mdx +++ b/problems/invalid_state.mdx @@ -10,7 +10,7 @@ description: "Not allowed in the current state. HTTP 422." | `type` | `https://docs.cortex.foundation/problems/invalid_state` | | Retryable | no | -The request is well-formed but the resource forbids it — for example cancelling a Code turn that already finished, or restoring a runtime that is `stopping`. +The request is well-formed but the resource forbids it — for example cancelling a Code turn that already finished, or restoring a runtime that is shutting down. ```json { @@ -24,6 +24,6 @@ The request is well-formed but the resource forbids it — for example cancellin ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/jurisdiction_restricted.mdx b/problems/jurisdiction_restricted.mdx index 13ee1ee..5694ee2 100644 --- a/problems/jurisdiction_restricted.mdx +++ b/problems/jurisdiction_restricted.mdx @@ -24,6 +24,6 @@ The region is not served, or an age gate has not been satisfied. ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/no_capacity.mdx b/problems/no_capacity.mdx index bece894..b054ffe 100644 --- a/problems/no_capacity.mdx +++ b/problems/no_capacity.mdx @@ -10,7 +10,7 @@ description: "No capacity for this model right now. HTTP 503." | `type` | `https://docs.cortex.foundation/problems/no_capacity` | | Retryable | yes | -Every inference backend for the requested model is unhealthy or circuit-broken. Operational, not a code defect. +Every backend that can serve the requested model is saturated. It is specific to one model, so a moment usually clears it and another model is normally still available. ```json { @@ -24,6 +24,6 @@ Every inference backend for the requested model is unhealthy or circuit-broken. ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/not_found.mdx b/problems/not_found.mdx index 228115f..5028332 100644 --- a/problems/not_found.mdx +++ b/problems/not_found.mdx @@ -24,6 +24,6 @@ No resource with that id is visible to this caller. Cross-account reads are 404 ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/payload_too_large.mdx b/problems/payload_too_large.mdx index cca8c0d..8bda8d2 100644 --- a/problems/payload_too_large.mdx +++ b/problems/payload_too_large.mdx @@ -10,7 +10,7 @@ description: "Payload too large. HTTP 413." | `type` | `https://docs.cortex.foundation/problems/payload_too_large` | | Retryable | no | -An upload exceeded the configured per-file or per-request ceiling. Chat and Library ingest cap at 10 MiB; bug-report screenshots at 4 MiB; transcribe at 25 MiB. +An upload was larger than the ceiling for the surface it arrived on. A chat or Library attachment can be at most 10 MB, a bug-report screenshot 4 MB, and a dictated audio clip 25 MiB. ```json { @@ -24,6 +24,6 @@ An upload exceeded the configured per-file or per-request ceiling. Chat and Libr ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/quota_exceeded.mdx b/problems/quota_exceeded.mdx index dfab444..d9a56ee 100644 --- a/problems/quota_exceeded.mdx +++ b/problems/quota_exceeded.mdx @@ -10,7 +10,7 @@ description: "Plan limit reached. HTTP 429." | `type` | `https://docs.cortex.foundation/problems/quota_exceeded` | | Retryable | no | -A plan quota window is exhausted. Carries `resets_at`, `retry_after_seconds`, `quota_key`, `plan`, and optionally `fallback_model`. Not retryable: wait for the window or upgrade. Free and Guest `images_per_day` is a quota, not a paywall. +A plan quota window is exhausted. Carries `resets_at`, `retry_after_seconds`, `quota_key`, `plan`, and optionally `fallback_model`. Not retryable: wait for the window to reset, or move to a plan with higher ceilings. Note that `images_per_day` is a quota rather than a paywall, because every plan including Guest can generate images, in different daily amounts. ```json { @@ -24,6 +24,6 @@ A plan quota window is exhausted. Carries `resets_at`, `retry_after_seconds`, `q ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/rate_limited.mdx b/problems/rate_limited.mdx index 4e5c6af..6bed9ae 100644 --- a/problems/rate_limited.mdx +++ b/problems/rate_limited.mdx @@ -10,7 +10,7 @@ description: "Too many requests. HTTP 429." | `type` | `https://docs.cortex.foundation/problems/rate_limited` | | Retryable | yes | -Transport-level throttling, unrelated to plan entitlements. Honour `retry_after_seconds` / `Retry-After`. Device-token polls that are too fast return this with `status: slow_down`. +Transport-level throttling, unrelated to plan entitlements. Honour `retry_after_seconds` / `Retry-After`. ```json { @@ -24,6 +24,6 @@ Transport-level throttling, unrelated to plan entitlements. Honour `retry_after_ ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/safety_intervention.mdx b/problems/safety_intervention.mdx index f4779c3..599fb95 100644 --- a/problems/safety_intervention.mdx +++ b/problems/safety_intervention.mdx @@ -24,6 +24,6 @@ Blocked by the crisis-intervention protocol. Always accompanied by referral reso ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/service_unavailable.mdx b/problems/service_unavailable.mdx index 32c2b35..c464067 100644 --- a/problems/service_unavailable.mdx +++ b/problems/service_unavailable.mdx @@ -10,7 +10,7 @@ description: "Temporarily unavailable. HTTP 503." | `type` | `https://docs.cortex.foundation/problems/service_unavailable` | | Retryable | yes | -Deliberately shedding load, draining for deploy, or a required dependency is not configured. Chat compaction that cannot summarise fails closed with this code rather than dropping turns. +A dependency the request needs is not configured, or the service is refusing work for now. Chat compaction that cannot summarise fails closed with this code rather than dropping turns. ```json { @@ -24,6 +24,6 @@ Deliberately shedding load, draining for deploy, or a required dependency is not ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/unauthenticated.mdx b/problems/unauthenticated.mdx index c33506a..91bd186 100644 --- a/problems/unauthenticated.mdx +++ b/problems/unauthenticated.mdx @@ -24,6 +24,6 @@ No sign-in was presented, or it was malformed. Using Chat without an account is ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/unsupported_media_type.mdx b/problems/unsupported_media_type.mdx index 7379669..3caa50a 100644 --- a/problems/unsupported_media_type.mdx +++ b/problems/unsupported_media_type.mdx @@ -24,6 +24,6 @@ description: "Unsupported media type. HTTP 415." ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/upstream_failure.mdx b/problems/upstream_failure.mdx index 051f431..aa5b1b5 100644 --- a/problems/upstream_failure.mdx +++ b/problems/upstream_failure.mdx @@ -24,6 +24,6 @@ A dependency Cortex does not control failed. The `detail` names a product surfac ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/upstream_timeout.mdx b/problems/upstream_timeout.mdx index 8712d9e..a4979a7 100644 --- a/problems/upstream_timeout.mdx +++ b/problems/upstream_timeout.mdx @@ -24,6 +24,6 @@ A dependency did not answer within its budget. Same product-language rule as `up ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/problems/validation_failed.mdx b/problems/validation_failed.mdx index 87c717e..bd0b638 100644 --- a/problems/validation_failed.mdx +++ b/problems/validation_failed.mdx @@ -24,6 +24,6 @@ Request body or parameters failed structural or semantic validation. Field failu ## Related -- [Errors](/api/errors) — how to branch on `code`, and what not to render from `detail`. -- [Problem catalog](/problems) — every code, its status, and whether retrying helps. -- [Troubleshooting](/getting-started/troubleshooting) — what a message in the product means. +- [Errors](/reference/errors) - how to branch on `code`, and what not to render from `detail`. +- [Problem catalog](/problems) - every code, its status, and whether retrying helps. +- [Troubleshooting](/getting-started/troubleshooting) - what a message in the product means. diff --git a/reference/errors.mdx b/reference/errors.mdx new file mode 100644 index 0000000..8c27d02 --- /dev/null +++ b/reference/errors.mdx @@ -0,0 +1,206 @@ +--- +title: "Errors" +description: "Every Cortex failure is an RFC 9457 problem document. Branch on code, quote the reference id, and know which fields are safe to show." +icon: "triangle-exclamation" +keywords: ["problem json", "error handling", "status codes"] +--- + +Every failure Cortex returns has the same shape: an RFC 9457 problem document, sent as `application/problem+json`. There is no second error format anywhere in the product, so one way of reading an error works on every surface, from Cortex Chat to Cortex Code to the Cortex CLI. + +This page explains the fields of a problem document, which of them are a contract and which are only prose, how to get from an error to the page that explains it, and what retrying does and does not fix. It then lists every code Cortex emits, with its HTTP status, whether retrying helps, and the message the product shows for it. + +## The shape of a problem document + +```json +{ + "type": "https://docs.cortex.foundation/problems/not_found", + "title": "Not found", + "status": 404, + "code": "not_found", + "detail": "No conversation with that id.", + "instance": "/v1/conversations", + "request_id": "req_…" +} +``` + +| Field | Always present | What it is | +| --- | --- | --- | +| `code` | Yes | A stable, machine-readable snake_case identifier. **This is the contract.** Branch on this and nothing else. | +| `type` | Yes | An absolute URL that resolves to the page for that code on this site. Stable, and safe to link. | +| `status` | Yes | The HTTP status, repeated inside the body so a logged document explains itself. | +| `title` | Yes | A short sentence in English. **Not part of the contract**, and it may change without notice. | +| `detail` | Sometimes | A sentence about this one occurrence. Omitted when there is nothing to add. Never parse it. | +| `instance` | Sometimes | The request path the failure happened on. | +| `request_id` | Yes | The correlation identifier. Always safe to show or log, and the value to quote to support. | +| `errors` | Only on `validation_failed` | One entry per rejected field. | +| `extensions` | Depends on the code | Typed extra members, flattened to the top level of the document. | + +## How to read one + +Read the four always-present fields in this order, and you have everything you need. + +- **`code` tells you what happened.** The same code means the same thing on every surface and in every product, which is why it is the only field worth writing logic against. +- **`type` tells you where it is explained.** The problem type base is `https://docs.cortex.foundation/problems`, and `type` is that base plus `/{code}`. So a `quota_exceeded` failure carries `type: "https://docs.cortex.foundation/problems/quota_exceeded"`, and following that URL lands on the page for it. Every code below has one. +- **`status` tells you the class of the failure**, and is the fastest way to sort a pile of errors into "my request was wrong", "I am not allowed", "I am going too fast" and "Cortex broke". It is not precise enough to act on: two different 429s mean two different things. +- **`request_id` tells you which request this was.** One id identifies one failed request. + +**`detail` is the part that varies.** The other fields are the same for every occurrence of a code, while `detail` describes this one occurrence, and it is written for a person reading raw output, not for a user interface. It may name a Cortex surface or a specific resource. Treat it as diagnostic text: log it, and do not build anything on its wording. + +## What is safe to show a user + +The web app never renders the wire `title` or `detail`. It looks the code up in its own message catalogue and shows that instead. Anything you build against these documents should do the same. + +- **Write your own copy per `code`.** The page for each code explains the situation in product language. +- **Do not render `detail` as the primary message.** It is not the user's message. +- **Exactly three codes may show `detail` as a secondary line**: `validation_failed`, `bad_request` and `invalid_state`. Even there it supplements the message rather than being it. +- **`internal` deliberately carries nothing.** A 500 arrives with a status, the generic title and a `request_id`, and never a `detail`, field errors or extensions. The reference id is the only actionable thing in it, and the product's own copy says so. + +### Errors never name a vendor + +Before any message reaches a user, an internal service name is converted into product language. What you will see is a Cortex surface, in one of two sentences: "`<phrase>` is temporarily unavailable." or "`<phrase>` did not respond in time." + +The phrases are product-facing and stable enough to recognise: Sign-in, The assistant, The audio service, Connected apps, The plugin service, The payments service, The memory service, The bot computer, The Code runtime, The remote host, Cortex Security, The model catalogue, Image generation, Document export, Literature search, Origin detection, and This feature as a fallback. No subprocessor is ever named in an error. + +## The reference id + +`request_id` is always present, and it is the one value in a problem document that is designed to be shown to a user. In the product it appears at the bottom of an error card as **Reference** followed by the id. That string is the same value as `request_id` in the document behind the card. + +<Steps> + <Step title="Read the error card"> + The line beginning **Reference** holds the id. + </Step> + <Step title="Copy it before you retry"> + A retry produces a new id. The one that matters is the id from the request that failed. + </Step> + <Step title="Quote it when you get in touch"> + One id identifies one request, which is what lets support find it. For an `internal` failure the copy already asks for this: "This was not your fault and it has been recorded. Quote the id below if you get in touch." + </Step> +</Steps> + +## Rejected fields + +`validation_failed` is the only code that carries per-field detail, as an `errors` array. Each entry has three keys. + +| Key | What it holds | +| --- | --- | +| `pointer` | A JSON Pointer (RFC 6901) to the member of the request that was rejected. | +| `code` | One of `too_long`, `required` or `not_one_of`. | +| `message` | A sentence for that one field. | + +The product renders its own sentence per field code: "This is longer than allowed.", "This is required.", "This is not one of the accepted values.", and "This was not accepted." for anything it does not recognise. Showing the field errors next to the fields they point at is the whole value of this code, so prefer that over a single summary message. + +## Typed extras, by code + +Some codes carry extra members alongside the standard fields. They are typed, so you can rely on them where the code says they appear. + +| Code | Member | What it holds | +| --- | --- | --- | +| `quota_exceeded` | `resets_at` | An RFC 3339 timestamp: when the window rolls over on its own. | +| `quota_exceeded` | `retry_after_seconds` | The same information in seconds. | +| `quota_exceeded` | `quota_key` | Which limit was reached, for example `quick_messages_per_day`. | +| `quota_exceeded` | `plan` | The plan the limit came from. | +| `quota_exceeded` | `fallback_model` | A model still available under the limit, when there is one. | +| `rate_limited` | `retry_after_seconds` | How long to wait. | +| `entitlement_required` | `entitlement` | The capability key that is missing, for example `private_model_routing`. | +| `entitlement_required` | `required_plan` | The plan that includes it. | +| `safety_intervention` | `referral` | Support resources, as a name, a contact and a note. This code always carries them. | + +## Every code Cortex emits + +Twenty-four codes, each with its own page. The **What the product shows** column is the heading a user actually reads in the app, so it is the fastest way to match an error you were sent a screenshot of to the code behind it. + +| Code | HTTP | Retryable | What the product shows | +| --- | --- | --- | --- | +| [`validation_failed`](/problems/validation_failed) | 422 | no | Check the highlighted fields | +| [`bad_request`](/problems/bad_request) | 400 | no | That request could not be understood | +| [`idempotency_key_reuse`](/problems/idempotency_key_reuse) | 400 | no | This looks like a duplicate | +| [`payload_too_large`](/problems/payload_too_large) | 413 | no | That is too large to send | +| [`unsupported_media_type`](/problems/unsupported_media_type) | 415 | no | That file type is not supported | +| [`unauthenticated`](/problems/unauthenticated) | 401 | no | Please sign in again | +| [`invalid_credential`](/problems/invalid_credential) | 401 | no | Those credentials were not accepted | +| [`forbidden`](/problems/forbidden) | 403 | no | You do not have access to this | +| [`entitlement_required`](/problems/entitlement_required) | 403 | no | Not included in your plan | +| [`not_found`](/problems/not_found) | 404 | no | Not found | +| [`conflict`](/problems/conflict) | 409 | **yes** | Something changed while you were working | +| [`gone`](/problems/gone) | 410 | no | This is no longer available | +| [`invalid_state`](/problems/invalid_state) | 422 | no | Not possible right now | +| [`quota_exceeded`](/problems/quota_exceeded) | 429 | no | You have used this plan limit | +| [`rate_limited`](/problems/rate_limited) | 429 | **yes** | Too many requests | +| [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | 429 | no | Too much running at once | +| [`safety_intervention`](/problems/safety_intervention) | 403 | no | Support is available | +| [`content_policy`](/problems/content_policy) | 403 | no | This request was declined | +| [`jurisdiction_restricted`](/problems/jurisdiction_restricted) | 403 | no | Not available in your region | +| [`internal`](/problems/internal) | 500 | **yes** | Something broke on our side | +| [`upstream_failure`](/problems/upstream_failure) | 502 | **yes** | The assistant failed | +| [`upstream_timeout`](/problems/upstream_timeout) | 504 | **yes** | The assistant took too long | +| [`service_unavailable`](/problems/service_unavailable) | 503 | **yes** | Cortex is temporarily unavailable | +| [`no_capacity`](/problems/no_capacity) | 503 | **yes** | No capacity for this model right now | + +Grouped by status, in the order you are most likely to meet them: + +| Status | Codes | +| --- | --- | +| 400 Bad request | `bad_request`, `idempotency_key_reuse` | +| 401 Not signed in | `unauthenticated`, `invalid_credential` | +| 403 Not permitted | `forbidden`, `entitlement_required`, `safety_intervention`, `content_policy`, `jurisdiction_restricted` | +| 404 / 409 / 410 | `not_found`, `conflict`, `gone` | +| 413 / 415 | `payload_too_large`, `unsupported_media_type` | +| 422 Unprocessable | `validation_failed`, `invalid_state` | +| 429 Too many | `quota_exceeded`, `rate_limited`, `concurrency_limit_reached` | +| 500 / 502 / 504 | `internal`, `upstream_failure`, `upstream_timeout` | +| 503 Unavailable | `service_unavailable`, `no_capacity` | + +A retired capability answers `gone` rather than pretending to work or disappearing into a 404, so `gone` is worth handling even if you have never seen it. + +## Retrying + +Seven codes are retryable: `conflict`, `rate_limited`, `internal`, `upstream_failure`, `upstream_timeout`, `service_unavailable` and `no_capacity`. For every other code the same request will fail the same way, and the request, the plan or the state has to change first. + +- **`rate_limited`** carries `retry_after_seconds`. Wait that long, then back off. The product shows either "You can try again in" a label, or "You can try again now." +- **`conflict`** is the one retryable 4xx. Something changed underneath you, so reload to pick up the current version and apply your change again. +- **`no_capacity`** is specific to one model. Try again shortly, or pick another model. When the document carries a `fallback_model`, the product offers **Continue with** that model as a button, which is a choice you make rather than a substitution made for you. +- **`internal`, `upstream_failure`, `upstream_timeout` and `service_unavailable`** are ours. Retry, keep the reference id, and check [System status](/reference/status) if it repeats. + +<Warning> +Two of the three 429s are **not** retryable, which is the most common mistake made against this contract. + +`quota_exceeded` means a plan window is used up. It carries `resets_at` and `retry_after_seconds`, but those say when the window rolls over, not when to retry the same call. Waiting for the reset or changing plan is what fixes it. + +`concurrency_limit_reached` means too much is already running on the account. The sensible action is to wait for a run to finish, which frees a slot, but retrying immediately does not help. +</Warning> + +## When it was not your fault + +Three codes are always Cortex's own problem: `internal`, `upstream_failure` and `upstream_timeout`. The product says so in as many words, because a user who has just lost a turn deserves to know whether to keep trying. Nothing is expected of you beyond keeping the reference id. A request that reached the assistant and came back an error often succeeds on a retry; one that timed out was abandoned rather than left hanging, and a shorter prompt usually gets through. + +## When there is no problem document + +If the request never reached Cortex, there is nothing to read. The product says **You appear to be offline** with "Nothing was sent. This works again as soon as the connection is back.", or **The request could not be completed** with "Something went wrong before the request finished. Trying again usually works." + +<Note> +A network failure is not a problem document. There is no `code` and no `request_id` to quote for one, so a report of "it just failed" with no reference id is usually this, not a Cortex error. +</Note> + +## Codes that are not problem codes + +Cortex Security records its own reasons when a pull-request review cannot run: `upstream_unconfigured`, `no_model_available`, `app_not_configured`, `diff_unavailable`, `nothing_to_review`, `installation_suspended` and `review_incomplete`. These are stored with the review and rendered as a sentence on the review itself. They are not HTTP problem codes, they never appear in a problem document, and they have no page in the catalogue. [Security troubleshooting](/security/troubleshooting) covers each of these situations and what to do about it. + +## Related + +<CardGroup cols={2}> + <Card title="Problem catalog" icon="list" href="/problems"> + Every code with its status and retry answer, and a page per code. + </Card> + <Card title="Limits and quotas" icon="gauge-high" href="/reference/limits"> + The windows behind `quota_exceeded`, and what resets when. + </Card> + <Card title="Troubleshooting" icon="life-ring" href="/getting-started/troubleshooting"> + What a message you see in the product means, by symptom. + </Card> + <Card title="System status" icon="chart-line" href="/reference/status"> + Whether something is down right now, which this page cannot tell you. + </Card> +</CardGroup> + +- [Models](/reference/models) for the model names behind `no_capacity` and `fallback_model`. +- [Security and privacy](/reference/security-and-privacy) for what is kept in a log alongside a reference id. diff --git a/reference/limits.mdx b/reference/limits.mdx new file mode 100644 index 0000000..10892e8 --- /dev/null +++ b/reference/limits.mdx @@ -0,0 +1,172 @@ +--- +title: "Limits and quotas" +description: "Every user-facing limit in one place: the message windows per plan, storage, images, exports, projects, file size and timeouts." +icon: "gauge-high" +--- + +A plan in Cortex is a set of ceilings, each one attached to a window. Two of those ceilings are counted on every turn you send, a third is counted when you create something, and the rest are plan attributes the product draws as a meter. Your own numbers, with their reset countdowns, are always in **Settings → Plan & billing**, and that is the place to check before you rely on a figure. + +This page collects every limit a user can meet, says which plan it belongs to, and is honest about the ones that depend on the plan or the deployment. Plan names here are the names the product shows: **Guest**, **Free**, **Go**, **Plus** and **Pro**. + +<Note> +Only the two message windows and the project count are enforced on the request path today. The other ceilings below are real plan attributes and the product shows them, but they are not what stops a turn. If you need to know what a specific account allows, read the meters in Settings rather than a table on a documentation site. +</Note> + +## Messages + +These are the limits that stop you sending. + +| Quota key | Meter label | Window | Guest | Free | Go | Plus | Pro | +| --- | --- | --- | --- | --- | --- | --- | --- | +| `quick_messages_per_day` | Messages today | 1 day | 100 | 500 | 1,000 | Unlimited | Unlimited | +| `quick_messages_per_month` | Messages this month | 30 days | 500 | 3,000 | 8,000 | Unlimited | Unlimited | + +Three things to know about how these two interact. + +- **A turn charges both windows**, and the first to exhaust wins. You can be blocked by the monthly window while the daily bar still has room, and the other way round. +- **Plus and Pro have no message limit at all.** "Unlimited" here means there is no ceiling to hit, not a number too large to print. +- **The Guest allowance belongs to the signed-out session, not to an account.** It does not carry over when you sign in. + +## What is not metered + +Reasoning, code runs in the sandbox and web searches are **not metered on any plan**, Guest and Free included. Every plan is limited only by the message windows. + +| Quota key | Meter label | Value on every plan | +| --- | --- | --- | +| `reasoning_runs_per_day` | Reasoning runs | Unlimited | +| `sandbox_executions_per_day` | Code runs | Unlimited | +| `web_searches_per_day` | Web searches | Unlimited | + +An unlimited quota draws no bar in Settings, so an absent meter is not a broken one. If you find older copy promising a number of reasoning runs, code runs or web searches a day, that copy is stale: those counters were retired and the open buckets cleared. + +## Other plan ceilings + +| Ceiling | Quota key | Guest | Free | Go | Plus | Pro | +| --- | --- | --- | --- | --- | --- | --- | +| Projects | `projects` | None | 3 | 5 | Unlimited | Unlimited | +| Images today | `images_per_day` | 2 | 15 | Not published | 100 | Unlimited | +| Exports today | `exports_per_day` | 2 | 15 | Not published | 100 | Unlimited | +| Library storage | `storage_bytes` | 200 MB | 500 MB | Not published | 20 GB | Unlimited | +| Parallel agents | `concurrent_agent_runs` | Not published | 1 | Not published | 10 | 50 | + +How to read that table: + +- **None** means the capability is not available on that plan, not that it is unlimited. A guest has no projects. +- **Not published** means the plan carries no value for that ceiling, so this page will not invent one. Check **Settings → Plan & billing** on an account on that plan. +- **Projects** is a count, not a rate. There is no window and nothing resets: it is how many you may hold at once. This is the one non-message ceiling that is actually checked when you act. +- **Library storage** is a total across the files you keep, counted in decimal bytes so it matches the number the product shows. It is a different thing from the per-file limit below. +- **Parallel agents** is a plan attribute that the product displays but does not currently enforce. The matching error code exists regardless, so handle it rather than assuming it can never arrive. +- **Images and exports** are quotas rather than paywalls. Every plan, Guest included, can generate an image and export a document, in different daily amounts. + +## Files and attachments + +| Limit | Value | Applies to | +| --- | --- | --- | +| Size of one file | 10 MB | Every plan that can attach | +| Text or Office documents inlined per turn | Up to 4 | Chat turns | +| Characters inlined per attachment | About 32,000 | Chat turns | + +Over the per-file ceiling you get [`payload_too_large`](/problems/payload_too_large), and the product says so in plain words: "Files can be at most 10 MB. Remove or shrink the attachment and try again." A file that is inside that ceiling but over what your own plan allows gives you the plan notice instead, headed "That attachment is over your plan’s size limit". + +Three more behaviours are worth knowing before you attach something large: + +- A photo is compressed automatically to come in under 8 MiB, and a short clip under 10 MiB, so you do not have to shrink media by hand. +- A text or Office document is read by inlining part of its text into the turn, which is why the per-attachment character figure above matters more than the file size for a long document. +- An encrypted or password-protected document **fails closed**. It is not parsed, and nothing from it reaches the model. + +See [Attachments and files](/chat/attachments) for what happens to a file after you send it, and [Library](/chat/library) for the storage total. + +## Tool rounds in one turn + +A turn can call tools, read the results and call again. That loop is bounded. + +| Surface | Rounds per turn | +| --- | --- | +| Cortex Chat | 8 | +| Cortex Code | 48 | +| Cortex Bot | No round counter | + +A Chat turn that would need more than eight rounds is better split into several turns. Cortex Code is given far more room because a coding task legitimately reads and edits many files on the way to one answer. + +## Timeouts + +Most requests are given up to a minute to finish, and are given up on after that. A streamed reply is the exception: it is not cut off at a minute, because an answer that takes longer to write than a minute is normal rather than a fault. + +<Note> +Which error code a timeout produces depends on where it happened, and Cortex does not publish a mapping. Read the `code` in the response rather than inferring it from the wait. [Errors](/reference/errors) explains the codes you may see. +</Note> + +## Rate limits + +Cortex does not publish a requests-per-minute figure, and this page will not invent one. Nothing you can do by hand in the app is fast enough to be worth pacing, so treat rate limiting as something to handle in code rather than something to plan around. + +[`rate_limited`](/problems/rate_limited) exists in the error contract and can be returned, so a client should handle it and wait for the `retry_after_seconds` the response carries. Do not confuse it with [`quota_exceeded`](/problems/quota_exceeded): one is arriving too fast, the other is a plan window running out. + +## Where to see your own numbers + +<Steps> + <Step title="Open Settings, then Plan & billing"> + The current plan is shown with a **CURRENT PLAN** badge, above the meters. + </Step> + <Step title="Read the meters"> + Each quota shows `{value} used` and, where a window applies, `Resets in {label}`. A quota that is unlimited on your plan has no bar at all. + </Step> + <Step title="Check storage separately"> + The **STORAGE** section shows how much of your Library allowance is in use. If it cannot load it says "Storage usage could not be loaded" and offers **Retry**. + </Step> + <Step title="Check tokens under Usage"> + Pick a **Usage window** of 7 days, 30 days or 90 days. Cortex Chat, Cortex Code and Cortex Bot are counted separately, anything that could not be attributed shows as **Unattributed**, and there is a **PER MODEL** breakdown. An empty window reads "No recorded tokens in this window." because empty windows stay zeros rather than being filled in with an estimate. + </Step> +</Steps> + +The tab carries its own caveat, and it is a good one to take literally: "Quota bars on this tab come from the plan, not a certificate." + +## When you reach a limit + +A used-up window is not shown as a generic error. You get a **Plan limit reached** notice reading "You have used everything this plan allows in the current window.", with `Resets in {label}`, `Current plan: {plan}` and, when a model is still available to you under the limit, **Continue with** that model. While the reset time is being worked out it says "Working out when this resets…", and once the window has rolled over it says "Your allowance has reset, try again". + +The heading names the window you exhausted: + +| Quota key | Heading you see | +| --- | --- | +| `quick_messages_per_day` | You have used today’s messages | +| `quick_messages_per_month` | You have used this month’s messages | +| `reasoning_runs_per_day` | You have used today’s reasoning runs | +| `web_searches_per_day` | You have used today’s web searches | +| `sandbox_executions_per_day` | You have used today’s code runs | +| `images_per_day` | You have used today’s image generations | +| `exports_per_day` | You have used today’s document exports | +| `projects` | You have reached your project limit | +| `attachment_bytes` | That attachment is over your plan’s size limit | +| `concurrent_agent_runs` | Too many agent runs at once | +| Anything else | You have reached a plan limit | + +Which code you get depends on why you were stopped: + +| What happened | Code | What fixes it | +| --- | --- | --- | +| A plan window is used up | [`quota_exceeded`](/problems/quota_exceeded) | Wait for the reset, or move to a plan with more room. Retrying does not help. | +| The plan does not include the capability at all | [`entitlement_required`](/problems/entitlement_required) | A plan that includes it. The notice names the capability. | +| Requests arrived faster than allowed | [`rate_limited`](/problems/rate_limited) | Waiting. This clears by itself. | +| Too much running at once | [`concurrency_limit_reached`](/problems/concurrency_limit_reached) | Let a run finish, which frees a slot. | +| A file is over the size ceiling | [`payload_too_large`](/problems/payload_too_large) | A smaller file. | + +<Warning> +`quota_exceeded` is a 429 but it is **not** retryable. It carries the seconds until the window rolls over, which is not the same as a retry delay. Hammering the same request will fail the same way until the window resets or the plan changes. +</Warning> + +## Spend controls + +Usage credits, top-ups and a spend cap are present in the interface but resolve to "Not available on this deployment" or "Not reported". There is nothing to configure there yet, and no way to buy capacity beyond what your plan includes. Plan changes themselves are made from **Settings → Plan & billing → Change plan**, which notes that "Switch anytime — changes take effect at the next billing cycle." + +## Limits that live with their feature + +Some ceilings belong to one capability rather than to your plan, and they are documented where you meet them: how many servers you may connect and how many tools they may contribute in [MCP servers](/chat/mcp-servers), how far a research run will read in [Deep Research](/chat/deep-research), and what a document export will accept in [Document export](/chat/document-export). + +## Related + +- [Plans and quotas](/getting-started/plans) for what each plan costs and how to change plan. +- [Errors](/reference/errors) for the problem document behind every limit message. +- [`quota_exceeded`](/problems/quota_exceeded) for the code a used-up window returns. +- [Models](/reference/models) for the context and output ceilings, which are per model rather than per plan. +- [Library](/chat/library) for what counts towards your storage total. diff --git a/reference/models.mdx b/reference/models.mdx new file mode 100644 index 0000000..eab9198 --- /dev/null +++ b/reference/models.mdx @@ -0,0 +1,109 @@ +--- +title: "Models" +description: "The models Cortex publishes today, what Preview means, the context and output budgets, and which model a conversation runs on." +icon: "microchip" +--- + +Cortex publishes a small catalogue of models, and everything in the product reads from that one list: the model chip in Cortex Chat, the card behind a generated image, the per-model breakdown in your usage, and the **Models** tab in Settings. The list is fetched from Cortex rather than built into the app, so what you see is what your account can actually use right now. + +This page is the reference for that catalogue. It covers the models published today, what the **Preview** badge means, how to read a context window and an output ceiling, how a model gets attached to a conversation, and what happens when the list cannot be loaded or a model cannot be reached. It also names the models that are no longer published, so you can recognise a stale reference when you find one. + +## The models published today + +Three rows, and every one of them is a preview. + +| Model | Identifier | Kind | Description in the product | Context | Maximum output | +| --- | --- | --- | --- | --- | --- | +| **Cortex 1 Mini** | `cortex-1-mini` | Chat | Preview — the model Cortex is serving today. | 262,144 | 32,768 | +| **Cortex Teutonic-1** | `cortex-teutonic-1` | Chat | Preview (under active training). | 32,768 | 16,384 | +| **Cortex-Image-1** | `cortex-image-1` | Image | Image generation for Cortex Chat. | 4,096 | 1,024 | + +Both chat models support reasoning and tool use. Neither advertises image understanding, which is worth knowing before you attach a picture and expect the model to read it. + +**Cortex 1 Mini** is the model a new conversation starts on. **Cortex Teutonic-1** is a second preview with a much smaller context window, still under active training. + +<Note> +Do not plan a long single generation around Cortex Teutonic-1. Its output ceiling is 16,384, and because it is still training there is no larger generation budget to rely on. Split long work across turns instead. +</Note> + +## What Preview means + +Every published model carries the **Preview** badge, so the badge is not a way of telling models apart today. It is a maturity signal about the model itself: new, and liable to change. It does not mean the model runs on a different or experimental path, and there is nothing to opt into or out of. + +Because all three rows are previews, treat output quality, speed and availability as things that can move. The [changelog](/changelog) is where a change to the catalogue is announced. + +## Context and output, in user terms + +Two numbers describe each chat model, and they answer different questions. + +- **Context** is how much the model can have in front of it for one turn. Everything in the turn counts: the conversation so far, your new message, the text pulled in from attachments, and the results of any tool the model called on the way to answering. When a long conversation starts to feel like it is forgetting the beginning, this is the ceiling you are meeting. +- **Maximum output** is the longest single answer the model can produce. It is a per-answer ceiling, not a daily budget, and it is not affected by your plan. + +Both are counted in tokens, the units a model reads and writes, which do not line up exactly with words or characters. The practical consequence of the difference between the two chat models is large: Cortex 1 Mini has room for a long document and a long conversation around it, while Cortex Teutonic-1 has roughly an eighth of that room. + +## The image model + +**Cortex-Image-1** is the model behind image generation in Chat. It is a different kind of row from the chat models, and the Chat model picker only lists chat models, so you will never find it there. You reach it by asking Chat for a picture, and the image card names it, on its own or followed by the time the generation took. + +See [Image generation](/chat/image-generation) for how to ask for a picture and what you can do with the result, and [Limits and quotas](/reference/limits) for how many images a day each plan allows. Image generation is metered as a quota rather than sold as a paid-plan feature. + +## Which model answers + +The model belongs to the conversation, not to your account and not to your plan. + +- A new conversation in Chat starts on **Cortex 1 Mini**. +- A conversation keeps the model it was created with for its whole life. When Cortex Teutonic-1 was added, existing conversations stayed where they were rather than being moved onto it. +- The model picker in Chat lists chat models only. See [Models and thinking](/chat/models) for the picker, the per-message override and the thinking levels. +- Usage is recorded per product and per model. **Settings → Plan & billing → Usage** splits it across Cortex Chat, Cortex Code and Cortex Bot, with a **PER MODEL** view inside the window you choose. + +<Note> +Which model each of the other products picks for a given piece of work is not published, and it is not something you set from this catalogue. Cortex Chat is the surface where the choice is yours. +</Note> + +## No plan gates, and no silent substitution + +Two facts about the catalogue matter more than any number in it. + +**No published model is behind a paid plan.** Every live row is available from the Free plan up, so you will not meet a locked row, and no plan buys you access to a model that another plan cannot reach. What a plan changes is how many messages you may send, which is covered in [Limits and quotas](/reference/limits). + +**No model has a configured fallback.** Cortex does not quietly answer with a different model from the one you chose. One consequence is that the two chat models fail independently: one preview can be unavailable while the other works normally. Another is that a failure reaches you instead of being absorbed, because a turn makes one attempt rather than looping through hidden retries. When that happens you get an upstream or a capacity code rather than a worse answer from somewhere else. + +| What you see | What it means | +| --- | --- | +| [`no_capacity`](/problems/no_capacity) | Every backend that can serve this model is saturated. A moment usually clears it, or pick the other model. | +| [`upstream_failure`](/problems/upstream_failure) | The request reached the assistant and came back an error. Retrying often works. | +| [`upstream_timeout`](/problems/upstream_timeout) | The request was abandoned rather than left hanging. A shorter prompt usually gets through. | + +Where a problem document offers a `fallback_model`, it is offered to you as a button, not applied for you. + +## When the model list will not load + +The composer depends on the list, so it tells you plainly rather than sending into the dark. + +| State | What the product says | +| --- | --- | +| Still loading | Loading the available models. | +| Could not be fetched | A reason, then "Sending is unavailable until the model list loads." | +| Loaded, but empty | No models are available on your account. | + +An empty list is not the same as a failed one. If you see "No models are available on your account.", check that you are signed in to the account you expect, then check [System status](/reference/status). + +## Models that are no longer published + +Three models were unpublished and are not available. You may still find them named in an old article, an old screenshot or an old conversation. + +| Model | State | +| --- | --- | +| Cortex 2 | Unpublished. Not selectable, and not served. | +| Cortex 2 Mini | Unpublished. Not selectable, and not served. | +| Cortex 1 Pro | Unpublished. Not selectable, and not served. | + +Conversations that had been running on them were moved to Cortex 1 Mini when they were withdrawn, so no conversation is stranded on a model that no longer exists. If a page or a post tells you one of these three is available, it is out of date. + +## Related + +- [Models and thinking](/chat/models) for the Chat model picker, the per-message override and thinking effort. +- [Image generation](/chat/image-generation) for what Cortex-Image-1 is used for. +- [Limits and quotas](/reference/limits) for the plan windows, which are the real ceiling on your use. +- [Errors](/reference/errors) for the codes a model failure returns, and what retrying fixes. +- [How Chat works](/chat/how-it-works) for what goes into a turn and how the context window is spent. diff --git a/reference/platform-api.mdx b/reference/platform-api.mdx new file mode 100644 index 0000000..5a1c2ae --- /dev/null +++ b/reference/platform-api.mdx @@ -0,0 +1,72 @@ +--- +title: "Platform API" +description: "Cortex has no public inference API today: no endpoints, no SDKs, no API keys. What the Platform API is not, and what to use instead" +icon: "clock" +keywords: ["inference API", "completions", "API keys", "SDK", "roadmap", "coming soon"] +--- + +Cortex does not have a public inference API. There is no endpoint that takes a prompt and returns a completion, no client library in any language, and no API key to request or generate. This page exists so the navigation does not grow a reference for something that is not there, and so you can stop looking. + +It is written for the reader who arrived wanting to call Cortex from their own code. That is a reasonable thing to want, and most requests that sound like an API call already have a product answer. This page says plainly what is missing, points you at the surface that does the job today, and says where an announcement would appear if that changes. + +## What is not available + +<Warning> +None of the following is in beta, in preview, or available on request. Each is simply absent. +</Warning> + +- **Model inference as a service.** Nothing takes a prompt over the network and returns a completion. +- **API keys and personal access tokens.** Nothing in the product issues one, so there is nothing to generate in Settings and nothing to paste into a client. +- **SDKs and client libraries.** None exist, in any language. +- **A third-party app model.** There is no way to register an application against a Cortex account and act on a user's behalf. +- **Teams, organisations and role-based access control.** Not available yet, so there is no programmatic surface to administer them. +- **An exportable audit log on the product API.** The entitlement exists for the **Pro** plan, but the log itself is not available yet. +- **Usage-based API billing.** There is no metered API to bill for. Your plan covers use of the products, and is described in [Limits and quotas](/reference/limits). + +## What to use instead + +Every row here is a product surface with its own sign-in, not an API key. + +| The API-shaped ask | What exists today | +| --- | --- | +| A one-shot prompt from a shell | The CLI: `cortex run`. See [Headless and one-shot runs](/cli/headless) | +| Scripted or piped invocation, including CI | The CLI: `cortex exec`. See [CI cookbook](/cli/ci) | +| Working inside a repository | A [Cortex Code](/code) session, or the CLI against a checkout | +| Recurring automated work | A [Cortex Bot](/bot) routine, described in [Routines](/bot/routines) | +| Letting Cortex call your own system | An [MCP server](/chat/mcp-servers) you connect | +| Reacting to a failure your integration sees | Branch on the error `code`. See [Errors](/reference/errors) | + +The CLI is the closest thing to an automation surface Cortex has. It runs non-interactively, it exits with a status your script can read, and it signs in as you rather than carrying a key you would have to store somewhere. If you were reaching for an API in order to put Cortex in a pipeline, start at [Headless and one-shot runs](/cli/headless). + +## What this site does document + +Two public contracts are documented here, and neither is an inference API. + +<CardGroup cols={2}> +<Card title="The error contract" icon="triangle-exclamation" href="/reference/errors"> +Every failure in every Cortex surface is a problem document with a stable `code`, a human title and a `request_id`. A client can branch on the code instead of parsing prose. The full list is the [problem catalog](/problems). +</Card> +<Card title="The Bounty transparency log" icon="scale-balanced" href="/bounty/public-api"> +The Cortex Bounty programme publishes a small set of read-only endpoints that need no credential and mint none for the caller. They report adjudicated reports and standings, and nothing else. +</Card> +</CardGroup> + +The transparency log is the only unauthenticated public surface on this site, and it is narrow on purpose: it exists so the subnet and anyone watching it can verify bounty verdicts. It is not a general-purpose read API for your account, and it never carries chat transcripts. + +## Why there is nothing to try + +It is worth being exact about this, because a hidden endpoint is a tempting theory. There is no private beta to be added to, no undocumented route that answers for a favoured account, and no key that support can hand out, because nothing in the product issues one. The absence is in the product, not in the documentation. A page or a reseller offering paid Platform API access is not selling something Cortex has. + +## When this changes + +A Platform API would be announced on the [changelog](/changelog) and at [cortex.foundation](https://cortex.foundation) first. Until an announcement exists, treat any tool or page claiming to sell Platform API access as unofficial. + +If your need is genuinely not covered by the CLI, a Code session, a Bot routine or an MCP server, that is a gap in the Platform API rather than a hidden endpoint, and it is worth reporting as one. See [Report a bug](/getting-started/report-a-bug). + +## Related + +- [Headless and one-shot runs](/cli/headless) - `cortex run` and `cortex exec`, the automation surface that exists. +- [CI cookbook](/cli/ci) - recipes for running Cortex from a pipeline. +- [Errors](/reference/errors) - the contract a client should branch on. +- [Transparency API](/bounty/public-api) - the one public, credential-free surface. +- [Changelog](/changelog) - where a Platform API launch would appear. diff --git a/reference/security-and-privacy.mdx b/reference/security-and-privacy.mdx new file mode 100644 index 0000000..152969b --- /dev/null +++ b/reference/security-and-privacy.mdx @@ -0,0 +1,147 @@ +--- +title: "Security and privacy" +description: "What Cortex stores and never stores, what stays on your device, how consent works across the products, and how export, deletion and retention behave" +icon: "user-shield" +keywords: ["privacy", "data", "cookies", "consent", "retention", "export", "delete"] +--- + +This page is the reference for **how Cortex handles your data**: what it keeps, what it never keeps, what stays on your own device, which consent each product asks for, and how long anything survives. It is written for someone deciding whether to put real work into Cortex, and for anyone who has to answer that question for a team. + +It is not a live availability page, and it is not the Cortex Security product that reviews pull requests. For the click-by-click version of the controls described here, see [Data and privacy](/getting-started/data-and-privacy). For whether something is down right now, see [System status](/reference/status). + +## What Cortex stores + +| Stored | Detail | +| --- | --- | +| **Account details** | Your email address and the account identifiers created when you sign in. If you pay, a customer reference and the plan. | +| **Conversations and attachments** | While chat history is on. Encrypted before they are stored, under a key that belongs to your account alone. | +| **Saved memories** | What you explicitly saved. Reviewable and deletable one by one. | +| **Usage counts** | How many messages, reasoning runs, searches and code runs you used against your plan. Counts, not content. | +| **Operational logs** | Request identifiers, timings, error codes and coarse client information. Message content is redacted where the log is written, not filtered afterwards. | +| **Safety records** | That a crisis referral was shown, its category and when. Never the message that triggered it. | +| **Billing records** | Kept as long as tax and accounting law requires, typically seven years. | + +The product states the same list in its own words under **Settings → Data & privacy**, in a card headed **WHAT WE STORE**. + +## What Cortex never stores + +- **The content of connected apps.** Cortex reads a connected app at question time and discards the data. Nothing from it is kept. +- **The text that triggered a crisis referral.** What is recorded is that a referral was shown, never what you wrote. +- **Advertising profiles.** Your content is not used to build one. +- **Anything sold or shared for advertising.** Cortex does not sell personal information and does not share it for cross-context behavioural advertising. That is why there is no "Do Not Sell" link on this site: there is nothing for it to switch off. + +Conversations are not used to train models. There is a control, **Improve the model**, that is off by default and would have to be on before any sample could be reviewed for that purpose. It is not a live setting yet, so treat its copy as a description of a control that is coming: `Off by default — your chats are never used without this setting.` + +## What stays on your device + +Three things are held in your browser or on your computer rather than on Cortex servers. + +| On your device | Detail | +| --- | --- | +| **Your cookie choice** | Stored on the device for one year, so the banner does not ask again. | +| **Trusted contact and date of birth** | `Trusted contact and date of birth are stored in this browser, not on our servers.` They are included in a data export so the export is complete, and they are removed when you erase your account. | +| **Computer history** | `On the desktop app, record which apps and sites this computer opened — times only, no screenshots or audio. Off by default. Private browsing is never logged.` In a browser the row reads `Recording runs in the Cortex desktop app, not in this browser.` | + +## Consent, product by product + +Cortex asks before it does something consequential, and each grant is scoped to the product you gave it to. + +| Control | Default | What it covers | +| --- | --- | --- | +| **Save chat history** | On | Conversations are kept in your account so you can pick them up on any device. | +| **Improve the model** | Off | Nothing is reviewed for training without it, and it is not a live setting yet. | +| **Memory** | Reviewable | Standing preferences and facts you share. Recall and writing can be turned off, sensitive topics can be excluded, and a retention window can be set. See [Memory](/chat/memory). | +| **Optional analytics** | Off | Off until you allow them, and no optional tracker is loaded in this build. | +| **Two-factor confirmation** | Per action | A signed-in account confirms an export or a deletion with its authenticator app. See [Two-factor authentication](/getting-started/two-factor). | + +Connected apps are scoped explicitly: you choose whether a connection is available to **Cortex Chat**, **Cortex Bot**, or both, and Bot never inherits a tool you did not assign to it. You stay signed in with the provider, and Cortex never sees your password for it. See [MCP servers](/chat/mcp-servers) and [Bot tools](/bot/tools). + +A guest cannot connect a plugin or an MCP server, hold a repository grant, create a bot, or open Code's working surface. That is fail-closed on purpose: a guest session cannot be returned to later to revoke a grant, so it is never allowed to create one. Signing in is how you get those capabilities, and you do it in the app: see [Accounts and sign-in](/getting-started/accounts). + +Temporary chats never read or write memory, and sensitive topics stay out of memory unless you turn them on. + +<Note> +Cortex tells you it is an AI without being asked. A disclosure appears before the first reply, a reminder appears every three hours of continued conversation, and asking outright always gets a straight answer. No instruction you give overrides that. The full text is published at [cortex.foundation/ai-disclosures](https://cortex.foundation/ai-disclosures). +</Note> + +## Where code runs, and what each surface can reach + +| Surface | Where it runs | What it can reach | +| --- | --- | --- | +| **Cortex Chat** | Cortex's own services | Files you attach, connected apps enabled for Chat, and pages its web tools fetch. Nothing outside your account and its Library. | +| Chat's Python tool | A small, untrusted snippet sandbox | The snippet only. No workspace, no repository. | +| **Cortex Code** in the cloud | An isolated cloud guest, headless | The one repository prepared for that session. | +| Code on your machine or an SSH host | Your computer or your host, from the desktop app or the CLI | The project directory you chose. | +| **Cortex Bot** | An isolated cloud guest with a desktop and a shell | That guest's desktop, browser and files, plus connected apps enabled for Bot. | +| **Cortex Security** | Reads the pull request in place | The change under review. It posts a check run and changes nothing. | + +The surfaces do not share a working area. Chat's Python tool cannot see a repository, a Code session cannot reach a bot's desktop, and a bot cannot read a Code session's files. Consequential steps ask first: in Bot through [Approvals](/bot/approvals), and in the CLI through its approval policy and sandbox, described in [Modes and permissions](/cli/modes-and-permissions). + +User-facing error text names a Cortex surface and never a supplier, so an outage message tells you which part of Cortex is unhappy and nothing else. See [Errors](/reference/errors). + +## Export and deletion + +**Export my data** builds a JSON file, `cortex-data-export.json`, and downloads it. Read what it is carefully, because "export everything we hold" sounds broader than it is: the file holds your account details, conversation **metadata**, your memories, and Library file **metadata**. It does not contain message bodies and it does not contain file bytes. A signed-in account also gets Code session metadata, the names of bots it owns, Design canvas metadata, project metadata and Cortex Data records, never a token. A guest export has none of those keys. + +**Delete all data** deactivates the account at once and schedules a permanent erasure after a 30-day grace period: `Deletion requested — your data will be permanently erased within 30 days. Signing in again during that time cancels it.` Once the erasure has started, signing in is refused. + +When the erasure runs, the key held for your account is destroyed first, so every stored copy of your conversations and attachments becomes unreadable at once, wherever it is. Records, files and the search indexes are then cleared. Backups that could still restore the account expire 35 days after the erasure runs, which the privacy policy states rather than implying an instant global wipe. One thing survives on purpose: a record that the deletion happened, holding one-way fingerprints and no content, so a restored backup can have the erasure replayed instead of quietly bringing an account back. + +Conversations, Chat library files and Design canvases you still hold are never pruned on a schedule. They stay until you delete them or delete the account. + +## How long things are kept + +| Record | Kept for | +| --- | --- | +| Your content: conversations, files, canvases | No expiry imposed. Until you delete it or close the account | +| Operational and application logs | 30 days | +| Routing decisions and code-run records | 30 days | +| Usage records | 1 year, for billing disputes | +| Safety records | 2 years | +| Data-request records | 3 years | +| Audit log | 90 days queryable, then archived for 15 months | +| Record that an erasure happened | Indefinitely, fingerprints only, never content | +| Billing records | As long as tax and accounting law requires, typically seven years | + +A data request gets a response within 45 days, with notice beforehand if an extension is needed. + +## Cookies and consent signals + +Every cookie Cortex sets is necessary to run the product, and none is for advertising. + +| Cookie | Purpose | Lifetime | +| --- | --- | --- | +| Session | `Holds your signed-in session, and is set only after you sign in.` | Seven days | +| Guest session | `Names an anonymous session so Chat works before you sign in. It is not an account.` | 180 days, not re-issued | +| Language | `Remembers the interface language you chose in Settings.` | One year | +| This choice | `Stores the cookie decision, on your device.` | One year | + +On a first visit the banner **Cookies on this site** offers **Necessary only** and **Allow optional**. Optional analytics stay off until you allow them, and this build loads no analytics script at all; the preference is recorded so that a tracker added later could not fire without it. If your browser sends a **Global Privacy Control** signal, the banner instead reads `Global Privacy Control honoured` and optional cookies stay off whatever an earlier choice said. + +## What this page does not claim + +Cortex claims no certification, and neither does the product. **Settings → Data & privacy** carries a **Compliance** section whose own lede is `What this deployment certifies — and what it does not.`, and it lists statuses rather than seals: `A status is not a certificate.` + +| Framework | Status as listed | +| --- | --- | +| SOC 2 Type II | `NOT CERTIFIED YET` — `No report on file. We will say so when one exists.` | +| GDPR readiness | `IN PROGRESS` — `Readiness work is tracked; no certification is claimed.` | +| HIPAA | `NOT CERTIFIED · BAA PATH` — `Not certified. PHI needs a signed BAA first.` | + +No framework is listed as certified, and no certificate is issued from that pane. A BAA can be requested from Settings; requesting one signs nothing. The defaults a covered entity would ask about are already on, listed as **PHI-SAFE DEFAULTS (ON)**: model training opt-out, retention minimized, and logging redacted, with those logs kept for 30 days. + +Data residency is pinned. This deployment runs in the US region and org data residency is fixed to it; the other region renders as `NOT OFFERED`, and there is no switch in the app: `Region changes are not available in the app: they require a new deployment and a scheduled migration window.` Where a capability is not offered where you are, requests answer with the [jurisdiction_restricted](/problems/jurisdiction_restricted) code. + +<Warning> +Cortex is not certified under SOC 2, GDPR or HIPAA. Read the statuses literally, and if that changes it will be announced on the [changelog](/changelog) and at [cortex.foundation](https://cortex.foundation) first. +</Warning> + +The legal documents are published outside the docs site: [cortex.foundation/privacy](https://cortex.foundation/privacy), [cortex.foundation/terms](https://cortex.foundation/terms) and [cortex.foundation/ai-disclosures](https://cortex.foundation/ai-disclosures), with the cookie policy alongside them. Where this page and a legal page differ in detail, the legal page is the binding text. + +## Related + +- [Data and privacy](/getting-started/data-and-privacy) - the same controls, step by step. +- [Accounts and sign-in](/getting-started/accounts) - what a guest and a signed-in account can each do. +- [Limits and quotas](/reference/limits) - what is counted against your plan. +- [Errors](/reference/errors) - why an error names a Cortex surface and nothing else. +- [System status](/reference/status) - availability, which this page is not about. diff --git a/reference/status.mdx b/reference/status.mdx new file mode 100644 index 0000000..1af8bb5 --- /dev/null +++ b/reference/status.mdx @@ -0,0 +1,75 @@ +--- +title: "System status" +description: "Live availability for Cortex Web, API, Chat, Code and Bot: what the status page reports, what to do during an incident, and how maintenance appears" +icon: "signal" +keywords: ["uptime", "outage", "incident", "maintenance", "availability"] +--- + +Cortex publishes live component health, incident history and scheduled maintenance on one public page: [status.cortex.foundation](https://status.cortex.foundation). That is the canonical address, it is the only one, and it is worth a bookmark before you need it. + +This page explains what that site reports, how to read it during an incident, what a planned maintenance window looks like from inside the app, and why a documentation page is never the place to find out whether something is down right now. + +## What the status page reports + +Five components, no more. The names stay product-facing, so you can match what you are seeing to a row without knowing anything about how Cortex is built. + +| Component | What it covers | +| --- | --- | +| **Web** | The Cortex website and signed-in app shell at [cortex.foundation](https://cortex.foundation) | +| **API** | Product API routes used by Chat, Code, Bot, Design and the CLI | +| **Chat** | Conversations, tools, Deep Research, images and related Chat services | +| **Code** | Code Cloud sessions, desktop and CLI coding agent backends, and related Code services | +| **Bot** | Bot computers, approvals, routines and related Bot services | + +An individual incident may mark one or more of these surfaces as affected, so a single event can show against **Chat** and **API** at the same time. There is no separate component for Cortex Design: the routes it depends on are part of **API**, and a canvas hosted from Chat or Code also depends on that product's component. + +The status page is the place for fleet-wide notices. Error text inside the product deliberately names a Cortex surface and nothing else, so when something broad is wrong the status page carries the explanation and the error card carries your reference. + +## During an incident + +<Steps> +<Step title="Check the banner in the product"> +A live incident is announced where you already are. Read the banner before you start debugging your own network. +</Step> +<Step title="Open the status page"> +Go to [status.cortex.foundation](https://status.cortex.foundation) and read the affected component: **Web**, **API**, **Chat**, **Code** or **Bot**. A component that is healthy rules out a whole class of causes. +</Step> +<Step title="Subscribe if you want the next update"> +Subscribe on that page for email updates. You are then told when the state changes instead of reloading the page. +</Step> +<Step title="Keep your reference"> +Note the `request_id` from any error you saw. The error card shows it on the line beginning **Reference**, and one id identifies one request. It is what makes a report about a single failure answerable afterwards. See [Errors](/reference/errors). +</Step> +</Steps> + +<Note> +Email is the only subscription channel documented for the status page. If you need another, check the options the status page itself offers rather than assuming one exists. +</Note> + +## Planned maintenance + +A planned window replaces the app with a maintenance screen instead of failing requests one at a time. It is titled `Cortex is taking a short break` and headed `We'll be right back`, it names the time Cortex expects to be back, and it counts down under `Time remaining`. When the window ends the screen reads `Coming back now` and the app returns. + +That screen is not an error, and there is nothing to retry while it is up. Announced windows and their times are published on the status page. + +## Documentation and status are different things + +Documentation describes intended behaviour. The status page describes current behaviour. A docs page cannot tell you whether a service is healthy at this moment, and it will never try to. + +| Resource | Use it for | +| --- | --- | +| [status.cortex.foundation](https://status.cortex.foundation) | Live uptime, open incidents, maintenance windows | +| [Troubleshooting](/getting-started/troubleshooting) | What a specific message in the product means and what to do next | +| [Problem catalog](/problems) | The error code behind a failed request, its HTTP status and whether it is worth retrying | +| [Security and privacy](/reference/security-and-privacy) | How data is handled, which is not an availability question | +| [Changelog](/changelog) | What shipped, which is not an outage | + +If the product is healthy on the status page and a single action still fails for you, the failure is specific rather than fleet-wide. Start from the code on the error card and the matching page in the [problem catalog](/problems), then from your product's troubleshooting page. + +## Related + +- [Troubleshooting](/getting-started/troubleshooting) - cross-product symptoms and what they mean. +- [Errors](/reference/errors) - the problem document behind a failed request, and the reference id to keep. +- [Problem catalog](/problems) - every error code with its status and retry guidance. +- [Security and privacy](/reference/security-and-privacy) - data handling, not availability. +- [Changelog](/changelog) - what shipped and when. diff --git a/scripts/check-docs-content.mjs b/scripts/check-docs-content.mjs new file mode 100644 index 0000000..af6f773 --- /dev/null +++ b/scripts/check-docs-content.mjs @@ -0,0 +1,289 @@ +#!/usr/bin/env node +/** + * Content checks for the documentation tree. + * + * `check-docs-site.mjs` checks the site's shape: that `docs.json` and the MDX tree agree + * both ways, that the problem pages match the backend's error enum, that no image or + * sign-in internal has crept in, and that every page has frontmatter. This script checks + * what is inside a page: + * + * - frontmatter completeness, the 160-character description ceiling Mintlify renders + * into meta tags, and titles that are unique across the site + * - the forbidden-vocabulary list: sign-in wire internals, image paths, third-party + * vendor and competitor names, and emoji + * - `/v1/` API paths, which belong only on the pages that document the API + * - internal links resolving to a real page, and external links staying inside the + * allowlist + * - every page closing with a "## Related" (or "## Next") section, so no page is a + * dead end, and carrying enough prose to be worth landing on + * - balanced MDX components, `icon=` on every `<Card>`, and a `<CardGroup>` on every + * section landing page + * + * Usage: + * node scripts/check-docs-content.mjs every page in docs.json + * node scripts/check-docs-content.mjs cli/headless one page (slug, no .mdx) + * + * Exits 1 on any failure, one line per failure: "<slug>: <message>". + */ +import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; +import { join, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = resolve(process.env.CORTEX_CHECK_ROOT ?? fileURLToPath(new URL('..', import.meta.url))); + +const FORBIDDEN = [ + // Sign-in wire internals. The public docs describe what a person does, never the + // protocol underneath it. + [/\/auth\//, 'auth path'], + [/\/oauth\//, 'oauth path'], + [/refresh_token/, 'refresh_token'], + [/cortex_rt/, 'cortex_rt'], + [/\bWorkOS\b/, 'WorkOS'], + [/client_secret/i, 'client_secret'], + [/docs\.cortex\.sh/, 'docs.cortex.sh'], + // No images anywhere in this site, by design. + [/\/images\//, 'image path'], + [/<img\b/i, '<img>'], + [/<Frame\b/, '<Frame>'], + [/!\[[^\]]*\]\(/, 'markdown image'], + [/^image:/m, 'image frontmatter'], + // Competitors and third-party vendors. Cortex documentation describes Cortex. + [/\bChatGPT\b/, 'competitor: ChatGPT'], + [/\bOpenAI\b/, 'competitor: OpenAI'], + [/\bClaude\b/, 'competitor: Claude'], + [/\bAnthropic\b/, 'competitor: Anthropic'], + [/\bGemini\b/, 'competitor: Gemini'], + [/\bCopilot\b/, 'competitor: Copilot'], + // "Cursor" is also a real interface noun, so the common noun uses are excused. + [/\bCursor\b(?! (?:keys|position|movement|blink|is|to|and|at|in|on|over|left|right|up|down))/, 'competitor: Cursor'], + [/\bCodex\b/, 'competitor: Codex'], + [/\bGrok\b/, 'Grok'], + [/\bQwen\b/, 'vendor: Qwen'], + [/\bLlama\b/, 'vendor: Llama'], + [/\bMistral\b/, 'vendor: Mistral'], + [/\bvLLM\b/, 'vendor: vLLM'], + [/\bSGLang\b/, 'vendor: SGLang'], + [/\bGroq\b/, 'vendor: Groq'], + [/\bPolly\b/, 'vendor: Polly'], + [/\bComposio\b/, 'vendor: Composio'], + [/\bPipedream\b/, 'vendor: Pipedream'], + [/\bStripe\b/, 'vendor: Stripe'], + [/\bAWS\b/, 'vendor: AWS'], + [/\bFirecracker\b/, 'vendor: Firecracker'], + [/\bgVisor\b/, 'vendor: gVisor'], + [/\bRedis\b/, 'vendor: Redis'], + [/\bPostgres(?:QL)?\b/, 'vendor: Postgres'], + [/\bKubernetes\b/, 'vendor: Kubernetes'], + [/\bHelm\b/, 'vendor: Helm'], + [/\bTerraform\b/, 'vendor: Terraform'], + [/\bCloudflare\b/, 'vendor: Cloudflare'], + [/\bGreptile\b/, 'vendor: Greptile'], + [/\bElectron\b/, 'vendor: Electron'], + [/\bNext\.js\b/, 'vendor: Next.js'], + [/\bSolidJS\b/, 'vendor: SolidJS'], + [/\bReact\b/, 'vendor: React'], + [/\bDataCrunch\b/i, 'vendor: DataCrunch'], + [/\bVerda\b/, 'vendor: Verda'], + [/\bTailscale\b/, 'vendor: Tailscale'], + [/\bOpenBao\b/, 'vendor: OpenBao'], + // U+2660-U+2667 (card suits) are excluded from the emoji range: the terminal + // interface draws the diamond as a row marker, so it is a product glyph inside a + // quoted string, not decoration. + [/[\u{1F300}-\u{1FAFF}\u{2600}-\u{265F}\u{2668}-\u{27BF}]/u, 'emoji'], +]; + +const COMPONENTS = [ + 'Steps', 'Step', 'Tabs', 'Tab', 'AccordionGroup', 'Accordion', 'CardGroup', 'Card', + 'Note', 'Tip', 'Warning', 'Info', 'Check', 'Update', +]; + +const EXTERNAL_ALLOWED = [ + /^https:\/\/(?:[a-z0-9-]+\.)*cortex\.foundation/, + /^https:\/\/github\.com\/CortexLM\//, +]; + +/** Every .mdx file in the tree, as a slug relative to the repository root. */ +function mdxSlugs(dir = ROOT, out = new Set()) { + for (const name of readdirSync(dir)) { + if (name === 'node_modules' || name === 'scripts' || name.startsWith('.')) continue; + const path = join(dir, name); + if (statSync(path).isDirectory()) mdxSlugs(path, out); + else if (name.endsWith('.mdx')) { + out.add(relative(ROOT, path).replace(/\\/g, '/').replace(/\.mdx$/, '')); + } + } + return out; +} + +/** Page slugs reachable from docs.json navigation, in navigation order. */ +function collectNavPages(node, out = []) { + if (node == null) return out; + if (typeof node === 'string') { + if (!node.startsWith('http') && !out.includes(node)) out.push(node); + return out; + } + if (Array.isArray(node)) { + for (const item of node) collectNavPages(item, out); + return out; + } + if (typeof node !== 'object') return out; + // A group's `root` is the page its title opens, and it is not repeated in `pages`. + if (typeof node.root === 'string') collectNavPages(node.root, out); + if (Array.isArray(node.pages)) collectNavPages(node.pages, out); + if (Array.isArray(node.groups)) collectNavPages(node.groups, out); + if (Array.isArray(node.tabs)) collectNavPages(node.tabs, out); + return out; +} + +/** + * Section landing pages, which need a <CardGroup> so the section has a visible index: + * the site index and every `<section>/index` page, plus any navigation group whose `root` + * is some other page. `problems/index` is excluded -- it indexes the error codes as a + * table, not as cards. + */ +function landingPages(navigation, slugs) { + const out = new Set(['index']); + const visit = (node) => { + if (node == null || typeof node !== 'object') return; + if (Array.isArray(node)) { for (const item of node) visit(item); return; } + if (typeof node.root === 'string') out.add(node.root); + visit(node.pages); + visit(node.groups); + visit(node.tabs); + }; + visit(navigation); + for (const slug of slugs) if (slug.endsWith('/index')) out.add(slug); + out.delete('problems/index'); + return out; +} + +function frontmatter(text) { + const m = /^---\n([\s\S]*?)\n---\n/.exec(text); + if (!m) return null; + const fm = {}; + for (const line of m[1].split('\n')) { + const kv = /^([a-zA-Z]+):\s*(.*)$/.exec(line); + if (kv) fm[kv[1]] = kv[2].replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'); + } + return { fm, body: text.slice(m[0].length) }; +} + +function checkPage(slug, ctx) { + const out = []; + const file = join(ROOT, `${slug}.mdx`); + if (!existsSync(file)) return [`${slug}: MISSING FILE`]; + const text = readFileSync(file, 'utf8').replace(/\r/g, ''); + const parsed = frontmatter(text); + if (!parsed) return [`${slug}: no frontmatter`]; + const { fm, body } = parsed; + + const isProblem = slug.startsWith('problems/'); + const isChangelog = slug === 'changelog'; + + if (!fm.title) out.push('frontmatter: missing title'); + else { + const prior = ctx.titles.get(fm.title); + if (prior !== undefined && prior !== slug) { + out.push(`frontmatter: title "${fm.title}" duplicates ${prior}`); + } + ctx.titles.set(fm.title, slug); + } + if (!fm.description) out.push('frontmatter: missing description'); + else if (fm.description.length > 160) { + out.push(`frontmatter: description is ${fm.description.length} chars (max 160)`); + } + if (!isProblem && !fm.icon) out.push('frontmatter: missing icon'); + + for (const [re, label] of FORBIDDEN) { + const m = re.exec(text); + if (m) { + const line = text.slice(0, m.index).split('\n').length; + const source = JSON.stringify(text.split('\n')[line - 1].slice(0, 100)); + out.push(`forbidden ${label} at line ${line}: ${source}`); + } + } + + // /v1 paths belong only on the pages that document the API. Whether a documented path + // is actually registered is checked against the backend by check-docs-site.mjs. + if (!ctx.apiPages.has(slug)) { + const noFences = text.replace(/```[\s\S]*?```/g, ''); + for (const m of noFences.matchAll(/\/v1\/[A-Za-z0-9._~/{}\-]+/g)) { + out.push(`API path ${m[0].replace(/[),.;]+$/g, '')} on a non-API page`); + } + } + + for (const m of body.matchAll(/(?:href=|\]\()"?(\/[A-Za-z0-9._\-/#?=]*)"?/g)) { + const raw = m[1].split('#')[0].split('?')[0]; + if (raw === '/' || raw === '') continue; + const target = raw.replace(/^\//, '').replace(/\/$/, '') || 'index'; + if (![target, `${target}/index`].some((c) => ctx.slugs.has(c))) { + out.push(`link to /${target} has no page`); + } + } + + for (const m of body.matchAll(/https?:\/\/[^\s)"'<>\]]+/g)) { + if (!EXTERNAL_ALLOWED.some((re) => re.test(m[0]))) { + out.push(`external link outside the allowlist: ${m[0]}`); + } + } + + if (!isProblem && !isChangelog) { + if (!/\n## (Related|Next)\b/.test(body)) { + out.push('missing closing "## Related" (or "## Next") section'); + } + const words = body.replace(/<[^>]+>/g, ' ').split(/\s+/).filter(Boolean).length; + if (words < 250) out.push(`thin page: ${words} words`); + } + + for (const tag of COMPONENTS) { + const opens = (body.match(new RegExp(`<${tag}(?=[\\s>])(?![^>]*\\/>)`, 'g')) || []).length; + const closes = (body.match(new RegExp(`</${tag}>`, 'g')) || []).length; + if (opens !== closes) out.push(`unbalanced <${tag}>: ${opens} open, ${closes} close`); + } + + // Every card carries an icon, because this site has no images to carry instead. + for (const m of body.matchAll(/<Card\b[^>]*>/g)) { + if (!/icon=/.test(m[0])) out.push(`<Card> without icon: ${m[0].slice(0, 80)}`); + } + + if (ctx.landing.has(slug) && !/<CardGroup/.test(body)) { + out.push('hub page without a <CardGroup>'); + } + + return out.map((s) => `${slug}: ${s}`); +} + +const parsed = JSON.parse(readFileSync(join(ROOT, 'docs.json'), 'utf8')); +const navigation = collectNavPages(parsed.navigation); +const slugs = mdxSlugs(); + +const apiPages = new Set(['reference/errors', 'bounty/public-api']); +for (const slug of slugs) if (slug.startsWith('problems/')) apiPages.add(slug); + +const ctx = { + slugs, + apiPages, + landing: landingPages(parsed.navigation, slugs), + titles: new Map(), +}; + +const args = process.argv.slice(2).map((a) => a.replace(/\.mdx$/, '').replace(/^\//, '')); +const targets = args.length ? args : navigation; + +// Title uniqueness is a whole-site property, so a single-page run still needs every +// other page's title in hand before it can judge its own. +if (args.length) { + for (const slug of navigation) { + if (targets.includes(slug) || !existsSync(join(ROOT, `${slug}.mdx`))) continue; + const p = frontmatter(readFileSync(join(ROOT, `${slug}.mdx`), 'utf8').replace(/\r/g, '')); + if (p?.fm.title) ctx.titles.set(p.fm.title, slug); + } +} + +const failures = targets.flatMap((slug) => checkPage(slug, ctx)); +if (failures.length) { + console.error(failures.join('\n')); + console.error(`\n${failures.length} problem(s)`); + process.exit(1); +} +console.log(`check-docs-content: ok (${targets.length} page(s))`); diff --git a/scripts/check-docs-site.mjs b/scripts/check-docs-site.mjs index f7447c2..670685c 100644 --- a/scripts/check-docs-site.mjs +++ b/scripts/check-docs-site.mjs @@ -5,24 +5,20 @@ * * # Why this exists * - * `PROBLEM_TYPE_BASE` is wire contract. It used to point at - * `docs.cortex.sh/problems`, a host that did not serve pages and is not the - * product domain. Moving it without pages, or documenting `/v1/…` paths the - * router does not register, is the same class of silent decay as an unmirrored - * `ErrorCode`. + * `PROBLEM_TYPE_BASE` is wire contract: every error the API returns carries a + * `type` URL under `https://docs.cortex.foundation/problems`, so each + * `ErrorCode` needs a page there, and no page may document a code the API does + * not emit. Documenting a `/v1/…` path the router does not register is the + * same class of silent decay. * - * This check is mechanical rather than a note in a contributing guide because - * the note is what would be ignored the next time someone adds a code or a - * "helpful" endpoint to a docs table. It also holds the top navbar to Home + - * Documentation (not Chat | Code | Bot product chrome) and home CTAs to ink, - * not a brand-green Install / `navbar.primary` button. Public MDX must not - * document `/auth/`, `/oauth/`, refresh tokens, WorkOS, or `cortex_rt`. A - * `docs.json` navigation entry must resolve to an MDX page — Mintlify will - * otherwise publish a sidebar link that 404s, and the rest of this job would - * still pass. - * - * Kubernetes labels and AWS tags under `deploy/` that use `cortex.sh/…` are - * internal identifiers and are not scanned. + * The site is end-user documentation. Public MDX must not document sign-in + * wire protocols (`/auth/`, `/oauth/`, refresh tokens, identity vendors, or the + * session cookie), and it carries no images: every page and card uses an + * icon. Navigation is `navigation.tabs`, one tab per application, so a reader + * picks the product from the navbar the way they would on any large docs site. + * Every navigation entry, group root, navbar link, and internal href must + * resolve to an MDX page — Mintlify would otherwise publish a link that 404s + * while the rest of this job stayed green. */ import { existsSync, readdirSync, readFileSync } from 'node:fs'; @@ -33,6 +29,7 @@ const ROOT = resolve(process.env.CORTEX_CHECK_ROOT ?? fileURLToPath(new URL('..' const BACKEND = process.argv[2] === undefined ? null : resolve(process.argv[2]); const EXPECTED_BASE = 'https://docs.cortex.foundation/problems'; const OPERATIONAL = new Set(['/healthz', '/readyz', '/startupz']); +const PRODUCT_TABS = ['Chat', 'Code', 'Bot', 'CLI', 'Design', 'Security']; const failures = []; @@ -80,41 +77,6 @@ function tsProblemBase(source) { return /export const PROBLEM_TYPE_BASE = '([^']+)'/.exec(source)?.[1] ?? null; } -const PRODUCT_CHROME = new Set(['Chat', 'Code', 'Bot', 'Design']); - -function assertDocsChrome(docsJson) { - let parsed; - try { - parsed = JSON.parse(docsJson); - } catch { - fail('docs.json is not JSON'); - return; - } - const links = parsed.navbar?.links; - if (!Array.isArray(links)) { - fail('docs.json navbar.links must include Home and Documentation'); - return; - } - const labels = links.map((link) => link?.label); - if (!labels.includes('Home') || !labels.includes('Documentation')) { - fail('docs.json navbar must be Home + Documentation, not product chrome'); - } - for (const label of labels) { - if (typeof label === 'string' && PRODUCT_CHROME.has(label)) { - fail( - `docs.json navbar.links must not include product chrome "${label}" (those are documentation tabs)`, - ); - } - } - if (parsed.navbar?.primary) { - fail( - 'docs.json navbar.primary is a brand-green CTA; docs CTAs are ink, not Install', - ); - } - assertPublicApiNav(parsed); - assertNavPagesExist(parsed); -} - const FORBIDDEN_AUTH_PAGES = ['api/authentication', 'api/oauth']; function pushNavSlug(raw, out) { @@ -136,9 +98,8 @@ function pushNavSlug(raw, out) { /** * Mintlify `pages` entries are either a slug string or a nested `{ group, pages }` - * object. `href` on navbar links and nav objects is the same contract: an - * internal path must resolve to MDX. Walking only `pages` strings is how a - * dead navbar `/missing-mintlify-page` href used to leave this job green. + * object. `href` on navbar links, anchors and nav objects is the same contract: + * an internal path must resolve to MDX. */ function collectNavPages(node, out = []) { if (node == null) return out; @@ -169,6 +130,8 @@ function navPages(parsed) { const out = collectNavPages(parsed.navigation); collectNavPages(parsed.navbar?.links, out); if (parsed.navbar?.primary) collectNavPages(parsed.navbar.primary, out); + collectNavPages(parsed.footer?.links, out); + for (const redirect of parsed.redirects ?? []) pushNavSlug(redirect?.destination, out); return out; } @@ -177,6 +140,38 @@ function navPageExists(slug) { return candidates.some((rel) => existsSync(join(ROOT, rel))); } +function assertDocsConfig(docsJson) { + let parsed; + try { + parsed = JSON.parse(docsJson); + } catch { + fail('docs.json is not JSON'); + return; + } + const tabs = parsed.navigation?.tabs; + if (!Array.isArray(tabs)) { + fail('docs.json navigation must be `navigation.tabs` (one tab per application)'); + } else { + const labels = tabs.map((tab) => tab?.tab); + for (const product of PRODUCT_TABS) { + if (!labels.includes(product)) fail(`docs.json navigation.tabs must carry a "${product}" tab`); + } + for (const tab of tabs) { + if (!tab?.icon) fail(`docs.json tab "${tab?.tab}" has no icon`); + for (const group of tab?.groups ?? []) { + if (!group?.icon) fail(`docs.json group "${group?.group}" in tab "${tab?.tab}" has no icon`); + } + } + } + if (parsed.theme !== 'mint') fail('docs.json theme must be "mint" (the Mintlify starter theme)'); + if (!parsed.favicon) fail('docs.json must set a favicon'); + for (const mode of ['light', 'dark']) { + if (typeof parsed.logo?.[mode] !== 'string') fail(`docs.json logo.${mode} is missing`); + } + assertPublicApiNav(parsed); + assertNavPagesExist(parsed); +} + function assertPublicApiNav(parsed) { const pages = navPages(parsed); for (const page of FORBIDDEN_AUTH_PAGES) { @@ -221,6 +216,63 @@ function assertNoAuthInternals(rel, text) { } } +const IMAGES = [ + { pattern: /<img\b/i, label: '<img>' }, + { pattern: /<Frame\b/, label: '<Frame>' }, + { pattern: /!\[[^\]]*\]\(/, label: 'a markdown image' }, + { pattern: /^image:/m, label: '`image:` frontmatter' }, + { pattern: /\/images\//, label: 'an /images/ path' }, +]; + +function assertNoImages(rel, text) { + if (!rel.endsWith('.mdx')) return; + for (const { pattern, label } of IMAGES) { + if (pattern.test(text)) { + fail(`${rel} uses ${label}; this site carries no images, use icons`); + } + } +} + +function frontmatter(text) { + const m = /^---\n([\s\S]*?)\n---\n/.exec(text); + if (m === null) return null; + const out = {}; + for (const line of m[1].split('\n')) { + const kv = /^([a-zA-Z]+):\s*(.*)$/.exec(line); + if (kv) out[kv[1]] = kv[2].replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'); + } + return out; +} + +function assertFrontmatter(rel, text, titles) { + if (!rel.endsWith('.mdx')) return; + const fm = frontmatter(text); + if (fm === null) { + fail(`${rel} has no frontmatter`); + return; + } + if (!fm.title) fail(`${rel} has no title`); + if (!fm.description) fail(`${rel} has no description`); + else if (fm.description.length > 160) fail(`${rel} description is ${fm.description.length} characters (max 160)`); + if (!rel.startsWith('problems/') && !fm.icon) fail(`${rel} has no icon (this site uses icons, not images)`); + if (fm.title) { + const other = titles.get(fm.title); + if (other !== undefined) fail(`${rel} repeats the title "${fm.title}" of ${other}`); + else titles.set(fm.title, rel); + } +} + +function internalHrefs(text) { + const body = text.replace(/```[\s\S]*?```/g, ''); + const out = new Set(); + for (const m of body.matchAll(/(?:href=|\]\()"?(\/[A-Za-z0-9._\-/#?=]*)"?/g)) { + const raw = m[1].split('#')[0].split('?')[0]; + if (raw === '/' || raw === '') continue; + out.add(raw.replace(/^\//, '').replace(/\/$/, '')); + } + return out; +} + function routerPaths(source) { const registered = new Set(); for (const m of source.matchAll(/\.route\(\s*"([^"]+)"/g)) { @@ -320,7 +372,7 @@ if (!existsSync(join(docsRoot, 'docs.json'))) { if (docsJson.includes('docs.cortex.sh')) { fail('docs.json still names docs.cortex.sh'); } - assertDocsChrome(docsJson); + assertDocsConfig(docsJson); } for (const rel of FORBIDDEN_AUTH_PAGES) { @@ -331,38 +383,26 @@ for (const rel of FORBIDDEN_AUTH_PAGES) { } } -const indexMdx = join(docsRoot, 'index.mdx'); -if (existsSync(indexMdx)) { - const index = readFileSync(indexMdx, 'utf8'); - if (/<Card\s[^>]*title="(Quickstart|Download|Install)"/.test(index)) { - fail( - 'index.mdx must not use a Mintlify Card as a brand-green home CTA', - ); - } - if (/\b(Quickstart|Download Cortex)\b/.test(index) && !index.includes('ink-btn')) { - fail('index.mdx home CTAs must use ink-btn, not Mintlify primary Cards'); - } - if (!existsSync(join(docsRoot, 'custom.css'))) { - fail('custom.css is missing (ink CTA styles)'); - } -} - const registered = routerPaths(routerRs); const registeredNorm = new Set([...registered].map(normalizePath)); const docsFiles = walk(docsRoot).filter((path) => /\.(mdx|md|json)$/.test(path)); +const titles = new Map(); for (const file of docsFiles) { - const rel = relative(ROOT, file); + const rel = relative(ROOT, file).split('\\').join('/'); + if (rel === 'README.md' || rel === 'AGENTS.md') continue; const text = readFileSync(file, 'utf8'); if (text.includes('docs.cortex.sh')) { fail(`${rel} names docs.cortex.sh (problem URIs belong on docs.cortex.foundation)`); } - if (rel.endsWith('.mdx') && text.includes('/images/frames/')) { - fail( - `${rel} uses a retired fake-app SVG plate under /images/frames/; use images/product/*.png or images/cli/`, - ); - } assertNoAuthInternals(rel, text); + assertNoImages(rel, text); + assertFrontmatter(rel, text, titles); + if (rel.endsWith('.mdx')) { + for (const slug of internalHrefs(text)) { + if (!navPageExists(slug)) fail(`${rel} links to /${slug}, which has no MDX page`); + } + } if (BACKEND === null) continue; for (const path of documentedV1Paths(text)) { const norm = normalizePath(path); diff --git a/scripts/generate-docs-frames.py b/scripts/generate-docs-frames.py deleted file mode 100644 index 47566f5..0000000 --- a/scripts/generate-docs-frames.py +++ /dev/null @@ -1,541 +0,0 @@ -#!/usr/bin/env python3 -"""RETIRED — do not generate abstract product-window SVGs. - -Guide heroes use real Cortex CLI media (`images/cli/`) or marked -`images/product/*.png` hooks for upcoming staging screenshots. - -This script is kept so the retired plates can be inspected. Running it -is an error unless `--force-write-retired-frames` is passed. -Tokens below are historical (cream / ink / #1F4945). -""" - -from __future__ import annotations - -import sys -from pathlib import Path - -OUT = Path(__file__).resolve().parents[1] / "images" / "frames" - -CREAM = "#FAF8F4" -INK = "#211F1C" -GREEN = "#1F4945" -RAIL = "#F3F0EA" -LINE = "#E3DFD7" -MUTED = "#6E6A62" -DARK = "#161412" -PANEL = "#1A1815" -HAIR = "#3A3A3A" -SELECT = "#E1E5DE" - - -def wallpaper(w: int = 960, h: int = 560) -> str: - trees = [] - for i, (x, y, r) in enumerate( - ((80, 430, 90), (180, 410, 70), (300, 440, 110), (720, 420, 95), (860, 400, 80)) - ): - trees.append( - f'<ellipse cx="{x}" cy="{y}" rx="{r}" ry="{int(r * 0.72)}" fill="{GREEN}" opacity="{0.18 + (i % 3) * 0.04}"/>' - ) - return f""" - <defs> - <linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"> - <stop offset="0" stop-color="#D7E4DC"/> - <stop offset="0.55" stop-color="#EFE8DC"/> - <stop offset="1" stop-color="#C4D0C4"/> - </linearGradient> - <radialGradient id="mist" cx="50%" cy="70%" r="60%"> - <stop offset="0" stop-color="{CREAM}" stop-opacity="0.35"/> - <stop offset="1" stop-color="{GREEN}" stop-opacity="0.12"/> - </radialGradient> - </defs> - <rect width="{w}" height="{h}" fill="url(#sky)"/> - <rect width="{w}" height="{h}" fill="url(#mist)"/> - <path d="M0 360 C120 320 220 390 360 350 C500 310 620 390 960 330 L960 {h} L0 {h} Z" fill="{GREEN}" opacity="0.22"/> - <path d="M0 400 C160 360 280 430 480 390 C680 350 780 430 960 380 L960 {h} L0 {h} Z" fill="{INK}" opacity="0.16"/> - {"".join(trees)} -""" - - -def traffic(x: int, y: int) -> str: - return f""" - <circle cx="{x}" cy="{y}" r="5" fill="#C4B8A8"/> - <circle cx="{x + 16}" cy="{y}" r="5" fill="#C4B8A8"/> - <circle cx="{x + 32}" cy="{y}" r="5" fill="{GREEN}"/> -""" - - -def macos_window( - x: int, - y: int, - w: int, - h: int, - title: str, - focused: bool = True, - dark: bool = False, -) -> tuple[str, int, int, int, int]: - """Return (svg, content_x, content_y, content_w, content_h).""" - fill = DARK if dark else CREAM - title_fill = PANEL if dark else RAIL - title_ink = CREAM if dark else INK - ring = ( - f'<rect x="{x - 3}" y="{y - 3}" width="{w + 6}" height="{h + 6}" rx="16" fill="none" stroke="{GREEN}" stroke-width="2"/>' - if focused - else "" - ) - chrome = f""" - {ring} - <rect x="{x}" y="{y}" width="{w}" height="{h}" rx="13" fill="{fill}"/> - <rect x="{x}" y="{y}" width="{w}" height="{h}" rx="13" fill="none" stroke="{INK}" stroke-width="1.5"/> - <rect x="{x + 2}" y="{y + 2}" width="{w - 4}" height="{h - 4}" rx="11" fill="none" stroke="{LINE if not dark else HAIR}" stroke-width="1"/> - <rect x="{x}" y="{y}" width="{w}" height="36" rx="13" fill="{title_fill}"/> - <rect x="{x}" y="{y + 24}" width="{w}" height="12" fill="{title_fill}"/> - <path d="M{x} {y + 36} H{x + w}" stroke="{INK if not dark else HAIR}" stroke-width="1"/> - <path d="M{x} {y + 37} H{x + w}" stroke="{LINE if not dark else "#2A2824"}" stroke-width="1"/> - {traffic(x + 18, y + 18)} - <text x="{x + w / 2}" y="{y + 23}" text-anchor="middle" font-family="Inter, ui-sans-serif, sans-serif" font-size="12" font-weight="600" fill="{title_ink}">{title}</text> -""" - return chrome, x + 12, y + 48, w - 24, h - 60 - - -def terminal_window(x: int, y: int, w: int, h: int, title: str) -> tuple[str, int, int, int, int]: - return macos_window(x, y, w, h, title, focused=True, dark=True) - - -def text(x, y, s, *, size=13, fill=INK, weight=500, family="Inter, ui-sans-serif, sans-serif", anchor="start"): - return ( - f'<text x="{x}" y="{y}" text-anchor="{anchor}" font-family="{family}" ' - f'font-size="{size}" font-weight="{weight}" fill="{fill}">{s}</text>' - ) - - -def mono(x, y, s, *, size=12, fill=CREAM, weight=500): - return text( - x, - y, - s, - size=size, - fill=fill, - weight=weight, - family="IBM Plex Mono, ui-monospace, monospace", - ) - - -def wrap(body: str, w: int = 960, h: int = 560, label: str = "Cortex") -> str: - return f'''<svg xmlns="http://www.w3.org/2000/svg" width="{w}" height="{h}" viewBox="0 0 {w} {h}" fill="none" role="img" aria-label="{label}"> -{wallpaper(w, h)} -{body} -</svg> -''' - - -def switcher() -> str: - chrome, cx, cy, cw, ch = macos_window(90, 70, 780, 420, "Cortex — cortex.foundation") - main = cx + 184 - pills = [] - for i, (name, on) in enumerate((("Chat", True), ("Code", False), ("Bot", False))): - px = main + 16 + i * 88 - bg = SELECT if on else "transparent" - ink = GREEN if on else MUTED - bar = f'<rect x="{px}" y="{cy + 8}" width="72" height="28" rx="7" fill="{bg}"/>' - if on: - bar += f'<rect x="{px}" y="{cy + 8}" width="3" height="28" rx="1.5" fill="{GREEN}"/>' - pills.append(bar + text(px + 36, cy + 27, name, size=13, fill=ink, weight=600, anchor="middle")) - composer = f''' - <rect x="{main + 16}" y="{cy + ch - 72}" width="{cx + cw - main - 40}" height="56" rx="12" fill="{RAIL}" stroke="{INK}" stroke-width="1"/> - <rect x="{main + 18}" y="{cy + ch - 70}" width="{cx + cw - main - 44}" height="52" rx="10" fill="none" stroke="{LINE}" stroke-width="1"/> - {text(main + 36, cy + ch - 38, "Ask Cortex anything…", size=14, fill=MUTED)} - <rect x="{cx + cw - 70}" y="{cy + ch - 58}" width="46" height="28" rx="8" fill="{INK}"/> - {text(cx + cw - 47, cy + ch - 39, "Send", size=11, fill=CREAM, weight=600, anchor="middle")} -''' - bubbles = f''' - <rect x="{main + 16}" y="{cy + 52}" width="280" height="44" rx="12" fill="{RAIL}"/> - {text(main + 32, cy + 79, "What can Cortex Chat do?", size=13, fill=INK)} - <rect x="{main + 16}" y="{cy + 108}" width="420" height="68" rx="12" fill="{CREAM}" stroke="{LINE}" stroke-width="1"/> - {text(main + 32, cy + 134, "Projects, documents, research, and pictures —", size=13, fill=INK)} - {text(main + 32, cy + 156, "before you sign in. Code and Bot need an account.", size=13, fill=INK)} -''' - sidebar = f''' - <rect x="{cx}" y="{cy}" width="168" height="{ch}" fill="{RAIL}"/> - <path d="M{cx + 168} {cy} V{cy + ch}" stroke="{LINE}" stroke-width="1"/> - {text(cx + 16, cy + 28, "New chat", size=12, fill=INK, weight=600)} - {text(cx + 16, cy + 56, "Projects", size=11, fill=MUTED, weight=600)} - <rect x="{cx + 10}" y="{cy + 68}" width="148" height="28" rx="7" fill="{SELECT}"/> - {text(cx + 22, cy + 87, "Launch notes", size=12, fill=GREEN, weight=600)} - {text(cx + 22, cy + 118, "Research brief", size=12, fill=MUTED)} - {text(cx + 22, cy + 146, "Image drafts", size=12, fill=MUTED)} -''' - return wrap( - chrome - + sidebar - + "".join(pills) - + bubbles - + composer, - label="Cortex product switcher in a macOS window", - ) - - -def chat_composer() -> str: - chrome, cx, cy, cw, ch = macos_window(80, 64, 800, 432, "Cortex Chat") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="200" height="{ch}" fill="{RAIL}"/> - <path d="M{cx + 200} {cy} V{cy + ch}" stroke="{LINE}"/> - {text(cx + 16, cy + 24, "New chat", size=13, fill=INK, weight=600)} - {text(cx + 16, cy + 54, "TODAY", size=10, fill=MUTED, weight=600)} - <rect x="{cx + 10}" y="{cy + 66}" width="180" height="30" rx="7" fill="{SELECT}"/> - <rect x="{cx + 10}" y="{cy + 66}" width="3" height="30" fill="{GREEN}"/> - {text(cx + 24, cy + 86, "First conversation", size=12, fill=GREEN, weight=600)} - {text(cx + 24, cy + 122, "Attach a brief", size=12, fill=MUTED)} - <rect x="{cx + 220}" y="{cy + 16}" width="{cw - 236}" height="220" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 240, cy + 48, "You", size=11, fill=MUTED, weight=600)} - {text(cx + 240, cy + 72, "Summarize this launch brief for the team.", size=14, fill=INK)} - {text(cx + 240, cy + 110, "Cortex", size=11, fill=GREEN, weight=600)} - {text(cx + 240, cy + 134, "Three outcomes, two risks, one open question.", size=14, fill=INK)} - {text(cx + 240, cy + 158, "I used the attached brief — not a pasted URL.", size=13, fill=MUTED)} - <rect x="{cx + 220}" y="{cy + ch - 78}" width="{cw - 236}" height="64" rx="12" fill="{RAIL}" stroke="{INK}" stroke-width="1.2"/> - <rect x="{cx + 222}" y="{cy + ch - 76}" width="{cw - 240}" height="60" rx="10" fill="none" stroke="{LINE}"/> - {text(cx + 240, cy + ch - 40, "Ask a follow-up, or attach another Library file…", size=13, fill=MUTED)} - <rect x="{cx + cw - 86}" y="{cy + ch - 62}" width="54" height="28" rx="8" fill="{INK}"/> - {text(cx + cw - 59, cy + ch - 43, "Send", size=11, fill=CREAM, weight=600, anchor="middle")} -''', - label="Cortex Chat composer in a macOS window", - ) - - -def chat_projects() -> str: - chrome, cx, cy, cw, ch = macos_window(70, 60, 820, 440, "Chat · Projects") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="220" height="{ch}" fill="{RAIL}"/> - {text(cx + 16, cy + 28, "Projects", size=14, fill=INK, weight=600)} - <rect x="{cx + 12}" y="{cy + 44}" width="196" height="36" rx="8" fill="{SELECT}"/> - <rect x="{cx + 12}" y="{cy + 44}" width="3" height="36" fill="{GREEN}"/> - {text(cx + 28, cy + 67, "Launch notes", size=13, fill=GREEN, weight=600)} - {text(cx + 28, cy + 112, "Research brief", size=13, fill=MUTED)} - {text(cx + 28, cy + 144, "Image drafts", size=13, fill=MUTED)} - {text(cx + 248, cy + 28, "Launch notes", size=16, fill=INK, weight=600)} - {text(cx + 248, cy + 52, "Threads and Library files stay in this folder.", size=13, fill=MUTED)} - <rect x="{cx + 248}" y="{cy + 72}" width="260" height="88" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 264, cy + 100, "Thread", size=11, fill=MUTED, weight=600)} - {text(cx + 264, cy + 124, "Outline the September launch", size=13, fill=INK)} - <rect x="{cx + 524}" y="{cy + 72}" width="260" height="88" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 540, cy + 100, "Library", size=11, fill=MUTED, weight=600)} - {text(cx + 540, cy + 124, "brief.pdf · pinned", size=13, fill=INK)} - <rect x="{cx + 248}" y="{cy + 176}" width="536" height="160" rx="10" fill="{RAIL}"/> - {text(cx + 268, cy + 210, "A project is a folder plus its chats —", size=14, fill=INK)} - {text(cx + 268, cy + 234, "not a second selected pill in the sidebar.", size=14, fill=INK)} - {text(cx + 268, cy + 270, "Memory is account-scoped. Design canvases are a different object.", size=13, fill=MUTED)} -''', - label="Chat projects folder in a macOS window", - ) - - -def chat_research() -> str: - chrome, cx, cy, cw, ch = macos_window(80, 56, 800, 448, "Chat · Deep Research") - return wrap( - chrome - + f''' - {text(cx + 8, cy + 20, "Stay in Chat · plan, then run", size=12, fill=MUTED, weight=600)} - <rect x="{cx}" y="{cy + 36}" width="{cw}" height="120" rx="10" fill="{RAIL}"/> - {text(cx + 20, cy + 68, "Research plan", size=13, fill=INK, weight=600)} - {text(cx + 20, cy + 94, "1. What shipped in Cortex Chat this month?", size=13, fill=INK)} - {text(cx + 20, cy + 118, "2. Which sources should we trust?", size=13, fill=INK)} - <rect x="{cx + cw - 120}" y="{cy + 56}" width="96" height="32" rx="8" fill="{INK}"/> - {text(cx + cw - 72, cy + 77, "Start", size=13, fill=CREAM, weight=600, anchor="middle")} - <rect x="{cx}" y="{cy + 172}" width="240" height="180" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 16, cy + 200, "Questions", size=12, fill=MUTED, weight=600)} - {text(cx + 16, cy + 228, "Up to 32", size=18, fill=INK, weight=600)} - {text(cx + 16, cy + 256, "8 in parallel", size=13, fill=MUTED)} - <rect x="{cx + 256}" y="{cy + 172}" width="240" height="180" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 272, cy + 200, "Sources", size=12, fill=MUTED, weight=600)} - {text(cx + 272, cy + 228, "Up to 80", size=18, fill=INK, weight=600)} - {text(cx + 272, cy + 256, "4 fetches each", size=13, fill=MUTED)} - <rect x="{cx + 512}" y="{cy + 172}" width="264" height="180" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 528, cy + 200, "Not a Code tool", size=12, fill=MUTED, weight=600)} - {text(cx + 528, cy + 228, "Chat turn only", size=18, fill=INK, weight=600)} - {text(cx + 528, cy + 256, "Code refuses research.", size=13, fill=MUTED)} -''', - label="Deep Research plan in a macOS window", - ) - - -def chat_images() -> str: - chrome, cx, cy, cw, ch = macos_window(90, 70, 780, 420, "Chat · Cortex-Image-1") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="{cw * 0.46}" height="{ch}" rx="10" fill="{RAIL}"/> - {text(cx + 20, cy + 36, "Improving prompt…", size=13, fill=MUTED)} - <rect x="{cx + 20}" y="{cy + 56}" width="{cw * 0.46 - 40}" height="{ch - 80}" rx="8" fill="{CREAM}" stroke="{LINE}"/> - <path d="M{cx + 70} {cy + 220} C{cx + 110} {cy + 160}, {cx + 160} {cy + 250}, {cx + 220} {cy + 180}" stroke="{GREEN}" stroke-width="3" fill="none"/> - <circle cx="{cx + 90}" cy="{cy + 140}" r="18" fill="{GREEN}" opacity="0.35"/> - {text(cx + cw * 0.46 + 24, cy + 40, "generate_image", size=12, fill=MUTED, weight=600)} - {text(cx + cw * 0.46 + 24, cy + 72, "A complete English scene", size=16, fill=INK, weight=600)} - {text(cx + cw * 0.46 + 24, cy + 104, "queued → generating → Library file", size=13, fill=MUTED)} - {text(cx + cw * 0.46 + 24, cy + 148, "Size, optional seed, steps 1–50", size=13, fill=INK)} - {text(cx + cw * 0.46 + 24, cy + 176, "Free and Guest: images_per_day quota", size=13, fill=INK)} - {text(cx + cw * 0.46 + 24, cy + 216, "Built on NVIDIA Cosmos", size=12, fill=MUTED)} - {text(cx + cw * 0.46 + 24, cy + 248, "Empty cluster URL fails closed", size=12, fill=MUTED)} - {text(cx + cw * 0.46 + 24, cy + 276, "before any quota is spent.", size=12, fill=MUTED)} -''', - label="Image generation card in a macOS window", - ) - - -def code_session() -> str: - chrome, cx, cy, cw, ch = macos_window(70, 56, 820, 448, "Cortex Code · session") - modes = "" - for i, (name, on) in enumerate((("Ask", False), ("Plan", False), ("Agent", True))): - px = cx + 220 + i * 92 - bg = SELECT if on else CREAM - ink = GREEN if on else MUTED - modes += f'<rect x="{px}" y="{cy + 12}" width="84" height="28" rx="8" fill="{bg}" stroke="{LINE}"/>' - modes += text(px + 42, cy + 31, name, size=12, fill=ink, weight=600, anchor="middle") - return wrap( - chrome - + modes - + f''' - <rect x="{cx}" y="{cy}" width="200" height="{ch}" fill="{RAIL}"/> - {text(cx + 16, cy + 28, "Timeline", size=12, fill=MUTED, weight=600)} - {text(cx + 16, cy + 56, "You · add /healthz + test", size=12, fill=INK)} - {text(cx + 16, cy + 84, "read src/router.rs", size=12, fill=MUTED)} - {text(cx + 16, cy + 112, "edit src/router.rs", size=12, fill=INK)} - {text(cx + 16, cy + 140, "bash cargo test", size=12, fill=MUTED)} - <rect x="{cx + 216}" y="{cy + 56}" width="{cw - 216}" height="200" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 236, cy + 88, "Agent can change the repository.", size=14, fill=INK, weight=600)} - {text(cx + 236, cy + 116, "Ask and Plan do not edit files or run shell.", size=13, fill=MUTED)} - {text(cx + 236, cy + 148, "Stop cancels the live turn. A follow-up can pick", size=13, fill=INK)} - {text(cx + 236, cy + 172, "a different mode. Web Code has no model picker.", size=13, fill=INK)} - <rect x="{cx + 216}" y="{cy + 272}" width="{cw - 216}" height="88" rx="10" fill="{DARK}"/> - {mono(cx + 236, cy + 308, "$ cargo test healthz", size=13, fill=CREAM)} - {mono(cx + 236, cy + 332, "ok healthz_returns_200", size=13, fill="#8AC5B9")} -''', - label="Code session timeline in a macOS window", - ) - - -def code_cloud() -> str: - chrome, cx, cy, cw, ch = macos_window(90, 70, 780, 420, "Cortex Code · Cloud guest") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="{cw / 2 - 10}" height="{ch}" rx="10" fill="{RAIL}"/> - {text(cx + 20, cy + 40, "Cloud guest", size=16, fill=INK, weight=600)} - {text(cx + 20, cy + 72, "Isolated Firecracker machine", size=13, fill=MUTED)} - {text(cx + 20, cy + 112, "read_file write_file edit_file", size=13, fill=INK)} - {text(cx + 20, cy + 140, "glob grep bash todos", size=13, fill=INK)} - {text(cx + 20, cy + 180, "Headless — no desktop", size=13, fill=MUTED)} - {text(cx + 20, cy + 208, "Not Chat’s Python sandbox", size=13, fill=MUTED)} - <rect x="{cx + cw / 2 + 10}" y="{cy}" width="{cw / 2 - 10}" height="{ch}" rx="10" fill="{DARK}"/> - {mono(cx + cw / 2 + 32, cy + 48, "prepare repository", fill="#8AC5B9")} - {mono(cx + cw / 2 + 32, cy + 76, "attach guest")} - {mono(cx + cw / 2 + 32, cy + 104, "snapshot ready")} - {mono(cx + cw / 2 + 32, cy + 148, "This PC / SSH", fill="#B0AAA0")} - {mono(cx + cw / 2 + 32, cy + 176, "desktop app and CLI only", fill="#B0AAA0")} - {mono(cx + cw / 2 + 32, cy + 220, "no Secrets page", fill="#B0AAA0")} -''', - label="Code Cloud guest in a macOS window", - ) - - -def bot_computer() -> str: - chrome, cx, cy, cw, ch = macos_window(60, 52, 840, 456, "Cortex Bot · Computer") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="{cw * 0.58}" height="{ch}" fill="{RAIL}"/> - {text(cx + 20, cy + 32, "Finch", size=16, fill=INK, weight=600)} - {text(cx + 20, cy + 56, "Conversation", size=12, fill=MUTED)} - <rect x="{cx + 16}" y="{cy + 76}" width="{cw * 0.58 - 32}" height="56" rx="10" fill="{CREAM}"/> - {text(cx + 32, cy + 110, "Open the weekly report and summarise it.", size=13, fill=INK)} - <rect x="{cx + 16}" y="{cy + 148}" width="{cw * 0.58 - 32}" height="56" rx="10" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 32, cy + 182, "Opening desktop… then I will take a screenshot.", size=13, fill=INK)} - <rect x="{cx + cw * 0.58 + 8}" y="{cy}" width="{cw * 0.42 - 8}" height="{ch}" fill="{DARK}"/> - {text(cx + cw * 0.58 + 24, cy + 32, "Computer", size=13, fill=CREAM, weight=600)} - {text(cx + cw * 0.58 + 24, cy + 56, "Cloud · live desktop", size=11, fill="#B0AAA0")} - <rect x="{cx + cw * 0.58 + 20}" y="{cy + 76}" width="{cw * 0.42 - 40}" height="200" rx="8" fill="#111110" stroke="{GREEN}" stroke-width="2"/> - <rect x="{cx + cw * 0.58 + 36}" y="{cy + 96}" width="120" height="16" rx="3" fill="{HAIR}"/> - <rect x="{cx + cw * 0.58 + 36}" y="{cy + 124}" width="80" height="48" rx="6" fill="{GREEN}" opacity="0.45"/> - <rect x="{cx + cw * 0.58 + 128}" y="{cy + 124}" width="80" height="48" rx="6" fill="{HAIR}"/> - {text(cx + cw * 0.58 + 24, cy + 308, "Open desktop", size=12, fill=CREAM, weight=600)} - {text(cx + cw * 0.58 + 24, cy + 332, "Sleep", size=12, fill="#B0AAA0")} - {text(cx + cw * 0.58 + 24, cy + 364, "Connecting only while starting.", size=11, fill="#B0AAA0")} -''', - label="Bot conversation and Computer rail in a macOS window", - ) - - -def design_canvas() -> str: - chrome, cx, cy, cw, ch = macos_window(70, 56, 820, 448, "Cortex Design · Untitled canvas") - return wrap( - chrome - + f''' - <rect x="{cx}" y="{cy}" width="{cw}" height="{ch}" rx="8" fill="{RAIL}"/> - <rect x="{cx + 24}" y="{cy + 24}" width="280" height="200" rx="8" fill="{CREAM}" stroke="{INK}" stroke-width="1.5"/> - <rect x="{cx + 26}" y="{cy + 26}" width="276" height="196" rx="6" fill="none" stroke="{GREEN}" stroke-width="2"/> - {text(cx + 40, cy + 56, "Frame 01", size=12, fill=MUTED, weight=600)} - <rect x="{cx + 40}" y="{cy + 72}" width="160" height="28" rx="6" fill="{INK}"/> - {text(cx + 120, cy + 91, "Primary", size=12, fill=CREAM, weight=600, anchor="middle")} - <rect x="{cx + 40}" y="{cy + 112}" width="200" height="12" rx="2" fill="{LINE}"/> - <rect x="{cx + 40}" y="{cy + 132}" width="168" height="12" rx="2" fill="{LINE}"/> - <rect x="{cx + 328}" y="{cy + 48}" width="220" height="140" rx="8" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + 344, cy + 80, "Note", size=12, fill=MUTED, weight=600)} - {text(cx + 344, cy + 108, "Hosted from Chat or Code.", size=13, fill=INK)} - {text(cx + 344, cy + 132, "Not a markdown sidecar.", size=13, fill=INK)} - <rect x="{cx + cw - 200}" y="{cy}" width="200" height="{ch}" fill="{CREAM}" stroke="{LINE}"/> - {text(cx + cw - 184, cy + 36, "Library", size=13, fill=INK, weight=600)} - {text(cx + cw - 184, cy + 68, "Components", size=12, fill=MUTED)} - {text(cx + cw - 184, cy + 92, "Pages", size=12, fill=MUTED)} - {text(cx + cw - 184, cy + 116, "Tokens", size=12, fill=MUTED)} - {text(cx + 24, cy + ch - 24, "Working UI is the Design desktop app.", size=12, fill=MUTED)} -''', - label="Design canvas with frames and library in a macOS window", - ) - - -def desktop() -> str: - chrome, cx, cy, cw, ch = macos_window(100, 80, 760, 400, "Cortex Desktop") - return wrap( - chrome - + f''' - {text(cx + 12, cy + 28, "This PC · SSH · Design", size=13, fill=MUTED, weight=600)} - <rect x="{cx}" y="{cy + 48}" width="230" height="240" rx="10" fill="{RAIL}" stroke="{LINE}"/> - {text(cx + 20, cy + 84, "This PC", size=15, fill=INK, weight=600)} - {text(cx + 20, cy + 112, "Paired host for Code", size=13, fill=MUTED)} - {text(cx + 20, cy + 136, "and Bot. Not in the browser.", size=13, fill=MUTED)} - <rect x="{cx + 250}" y="{cy + 48}" width="230" height="240" rx="10" fill="{RAIL}" stroke="{LINE}"/> - {text(cx + 270, cy + 84, "SSH", size=15, fill=INK, weight=600)} - {text(cx + 270, cy + 112, "A registered host.", size=13, fill=MUTED)} - {text(cx + 270, cy + 136, "Shell only, no desktop.", size=13, fill=MUTED)} - <rect x="{cx + 500}" y="{cy + 48}" width="236" height="240" rx="10" fill="{RAIL}" stroke="{GREEN}" stroke-width="2"/> - {text(cx + 520, cy + 84, "Design", size=15, fill=GREEN, weight=600)} - {text(cx + 520, cy + 112, "Working UI lives here.", size=13, fill=INK)} - {text(cx + 520, cy + 136, "No /design web mode.", size=13, fill=MUTED)} -''', - label="Cortex desktop surfaces in a macOS window", - ) - - -def cli_terminal() -> str: - chrome, cx, cy, cw, ch = terminal_window(80, 56, 800, 448, "cortex — Cortex CLI — 120×40") - return wrap( - chrome - + f''' - {mono(cx + 8, cy + 28, "Welcome to Cortex, the coding agent CLI", size=14)} - {mono(cx + 8, cy + 56, "v0.1 · / commands · Enter to send", size=12, fill="#B0AAA0")} - <path d="M{cx} {cy + ch - 92} H{cx + cw}" stroke="{HAIR}"/> - <path d="M{cx} {cy + ch - 90} H{cx + cw}" stroke="#2A2824"/> - {mono(cx + 8, cy + ch - 58, "> add a /healthz endpoint and cover it with a test", size=13)} - <rect x="{cx + 8}" y="{cy + ch - 70}" width="8" height="16" fill="{GREEN}"/> - <path d="M{cx} {cy + ch - 36} H{cx + cw}" stroke="{HAIR}"/> - <path d="M{cx} {cy + ch - 34} H{cx + cw}" stroke="#2A2824"/> - {mono(cx + 8, cy + ch - 12, "Cortex Mini 1", size=11, fill="#B0AAA0")} - <text x="{cx + cw - 8}" y="{cy + ch - 12}" text-anchor="end" font-family="IBM Plex Mono, ui-monospace, monospace" font-size="11" fill="#B0AAA0">? help</text> -''', - label="Cortex CLI terminal frame", - ) - - -def security() -> str: - chrome, cx, cy, cw, ch = macos_window(80, 64, 800, 432, "Where code runs") - boxes = [] - for i, (title, body) in enumerate( - ( - ("Chat Python", "Small snippet sandbox.\nNo workspace."), - ("Code Cloud", "Isolated guest.\nHeadless."), - ("Bot computer", "Isolated guest.\nDesktop + shell."), - ) - ): - bx = cx + 16 + i * 250 - boxes.append( - f''' - <rect x="{bx}" y="{cy + 36}" width="232" height="220" rx="12" fill="{RAIL}" stroke="{LINE}"/> - <rect x="{bx}" y="{cy + 36}" width="232" height="6" rx="3" fill="{GREEN}"/> - {text(bx + 16, cy + 80, title, size=16, fill=INK, weight=600)} - {text(bx + 16, cy + 116, body.splitlines()[0], size=13, fill=MUTED)} - {text(bx + 16, cy + 140, body.splitlines()[1], size=13, fill=MUTED)} -''' - ) - return wrap( - chrome - + "".join(boxes) - + text(cx + 16, cy + 300, "Do not mix them. Chat Python cannot see a Code repository.", size=13, fill=INK), - label="Three Cortex sandboxes in a macOS window", - ) - - -def approvals() -> str: - chrome, cx, cy, cw, ch = macos_window(140, 90, 680, 380, "Bot · Confirm") - return wrap( - chrome - + f''' - {text(cx + 24, cy + 40, "Allow this computer step?", size=18, fill=INK, weight=600)} - {text(cx + 24, cy + 72, "Confirming runs the parked action.", size=14, fill=MUTED)} - <rect x="{cx + 24}" y="{cy + 110}" width="{cw - 48}" height="72" rx="10" fill="{RAIL}"/> - {text(cx + 40, cy + 154, "grounded_click · Submit form", size=14, fill=INK)} - <rect x="{cx + 24}" y="{cy + 210}" width="140" height="40" rx="8" fill="{INK}"/> - {text(cx + 94, cy + 236, "Allow", size=14, fill=CREAM, weight=600, anchor="middle")} - <rect x="{cx + 176}" y="{cy + 210}" width="140" height="40" rx="8" fill="{CREAM}" stroke="{INK}"/> - {text(cx + 246, cy + 236, "Deny", size=14, fill=INK, weight=600, anchor="middle")} - <rect x="{cx + 328}" y="{cy + 210}" width="160" height="40" rx="8" fill="{SELECT}" stroke="{GREEN}" stroke-width="2"/> - {text(cx + 408, cy + 236, "Always", size=14, fill=GREEN, weight=600, anchor="middle")} -''', - label="Bot approval Allow Deny Always in a macOS window", - ) - - -def github() -> str: - chrome, cx, cy, cw, ch = macos_window(100, 80, 760, 400, "Code · Connect GitHub") - return wrap( - chrome - + f''' - {text(cx + 20, cy + 40, "Connect GitHub", size=20, fill=INK, weight=600)} - {text(cx + 20, cy + 76, "Code Home · repository picker · Settings → Integrations", size=13, fill=MUTED)} - <rect x="{cx + 20}" y="{cy + 110}" width="280" height="48" rx="10" fill="{INK}"/> - {text(cx + 160, cy + 140, "Connect GitHub", size=14, fill=CREAM, weight=600, anchor="middle")} - <rect x="{cx + 320}" y="{cy + 110}" width="200" height="48" rx="10" fill="{RAIL}" stroke="{LINE}"/> - {text(cx + 420, cy + 140, "Reconnect", size=14, fill=INK, weight=600, anchor="middle")} - {text(cx + 20, cy + 200, "There is no personal-access-token field.", size=14, fill=INK)} - {text(cx + 20, cy + 228, "If GitHub is unavailable on this deployment,", size=14, fill=MUTED)} - {text(cx + 20, cy + 256, "the product draws no Connect control.", size=14, fill=MUTED)} -''', - label="Connect GitHub control in a macOS window", - ) - - -FRAMES = { - "switcher.svg": switcher, - "chat-composer.svg": chat_composer, - "chat-projects.svg": chat_projects, - "chat-research.svg": chat_research, - "chat-images.svg": chat_images, - "code-session.svg": code_session, - "code-cloud.svg": code_cloud, - "bot-computer.svg": bot_computer, - "design-canvas.svg": design_canvas, - "desktop.svg": desktop, - "cli-terminal.svg": cli_terminal, - "security.svg": security, - "approvals.svg": approvals, - "github.svg": github, -} - - -def main() -> None: - if "--force-write-retired-frames" not in sys.argv: - sys.stderr.write( - "generate-docs-frames.py is retired. Do not add abstract product-window " - "SVGs. Use images/cli/ or overwrite images/product/*.png.\n" - ) - raise SystemExit(2) - OUT.mkdir(parents=True, exist_ok=True) - for name, fn in FRAMES.items(): - path = OUT / name - path.write_text(fn(), encoding="utf-8") - print(f"wrote {path.relative_to(OUT.parent.parent)}") - - -if __name__ == "__main__": - main() diff --git a/scripts/tests/check-docs-content.test.sh b/scripts/tests/check-docs-content.test.sh new file mode 100644 index 0000000..a284c53 --- /dev/null +++ b/scripts/tests/check-docs-content.test.sh @@ -0,0 +1,263 @@ +#!/usr/bin/env bash +# Holds scripts/check-docs-content.mjs. A throwaway site with one hub, one page and two +# problem pages is enough to prove that a clean tree passes and that every rule the +# script claims to enforce actually fires: frontmatter, the description ceiling, +# duplicate titles, forbidden vocabulary, emoji, API paths off the API pages, dead +# links, unallowed external links, the closing section, page length, unbalanced +# components, iconless cards and a hub with no card grid. +# +# It also pins the two deliberate exemptions, which are the ones a future edit is most +# likely to break by accident: the card-suit block is not emoji, and problem pages are +# exempt from the icon, closing-section and length rules. +set -euo pipefail + +root="$(cd "$(dirname "$0")/../.." && pwd)" +script="$root/scripts/check-docs-content.mjs" + +fail() { echo "check-docs-content.test.sh: $*" >&2; exit 1; } + +tmp="$(mktemp -d)" +cleanup() { rm -rf "$tmp"; } +trap cleanup EXIT + +# The word-count rule wants 250; this is 450. +filler() { + local i + for i in $(seq 1 30); do + printf 'The documentation describes what the product does and how a reader uses it. ' + done + printf '\n' +} + +seed() { + local dest="$1" + mkdir -p "$dest/site/guide" "$dest/site/problems" + + cat > "$dest/site/index.mdx" <<'MDX' +--- +title: "Cortex Docs" +description: "Everything Cortex does, one section per application." +icon: "house" +--- + +Pick an application. + +<CardGroup cols={2}> + <Card title="Guide" icon="book" href="/guide/thing"> + How the thing works. + </Card> +</CardGroup> + +MDX + filler >> "$dest/site/index.mdx" + printf '\n## Related\n\n- [Thing](/guide/thing)\n' >> "$dest/site/index.mdx" + + cat > "$dest/site/guide/thing.mdx" <<'MDX' +--- +title: "The thing" +description: "What the thing is and how to use it." +icon: "wrench" +--- + +<Steps> + <Step title="Open it"> + Open the thing. + </Step> +</Steps> + +MDX + filler >> "$dest/site/guide/thing.mdx" + printf '\n## Related\n\n- [Home](/)\n' >> "$dest/site/guide/thing.mdx" + + # The error index is a table of codes, not a card grid, so it is not a hub. + cat > "$dest/site/problems/index.mdx" <<'MDX' +--- +title: "Problem types" +description: "Every error code this API can return." +icon: "triangle-exclamation" +--- + +| Code | Meaning | +| --- | --- | +| `not_found` | Nothing at that address. | + +MDX + filler >> "$dest/site/problems/index.mdx" + printf '\n## Related\n\n- [Home](/)\n' >> "$dest/site/problems/index.mdx" + + # A problem page: no icon, no closing section, far under 250 words, and an API path. + cat > "$dest/site/problems/not_found.mdx" <<'MDX' +--- +title: "not_found" +description: "Nothing exists at that address." +--- + +Returned by `GET /v1/conversations/{id}` when the conversation is gone. +MDX + + cat > "$dest/site/docs.json" <<'JSON' +{ + "theme": "mint", + "name": "Cortex", + "navigation": { + "tabs": [ + { + "tab": "Get started", + "icon": "rocket", + "groups": [ + { "group": "Welcome", "icon": "hand-wave", "pages": ["index", "guide/thing"] } + ] + }, + { + "tab": "Reference", + "icon": "book-open", + "groups": [ + { + "group": "Errors", + "icon": "triangle-exclamation", + "root": "problems/index", + "pages": ["problems/not_found"] + } + ] + } + ] + } +} +JSON +} + +run() { CORTEX_CHECK_ROOT="$1/site" node "$script" "${@:2}" 2>&1; } + +must_fail() { + local dir="$1" needle="$2" out + if out="$(run "$dir")"; then + fail "expected failure mentioning ${needle}, got success: ${out}" + fi + printf '%s' "$out" | grep -q -- "$needle" || fail "expected output to mention ${needle}, got: ${out}" +} + +# A throwaway copy of the happy tree, so each case starts from a clean site. +fresh() { + local dir="$tmp/$1" + cp -r "$tmp/happy" "$dir" + printf '%s' "$dir" +} + +# --- happy path ------------------------------------------------------------------ +happy="$tmp/happy" +seed "$happy" +out="$(run "$happy")" || fail "happy tree should pass, got: $out" +[[ "$out" == *"4 page(s)"* ]] || fail "expected all four pages to be checked, got: $out" + +# Page count comes from docs.json navigation, group roots included. A page the +# navigation does not reach is not checked, and check-docs-site.mjs is what catches it. +out="$(run "$happy" guide/thing)" || fail "single-page run should pass, got: $out" +[[ "$out" == *"1 page(s)"* ]] || fail "expected a one-page run, got: $out" + +# The site is independent of the caller's directory. +out="$(cd "$tmp" && CORTEX_CHECK_ROOT="$happy/site" node "$script" 2>&1)" || + fail "standalone run should pass, got: $out" + +# CRLF is what the real tree uses; frontmatter must still parse. +crlf="$(fresh crlf)" +sed -i 's/$/\r/' "$crlf/site/guide/thing.mdx" +out="$(run "$crlf")" || fail "CRLF page should pass, got: $out" + +# --- frontmatter ----------------------------------------------------------------- +d="$(fresh no-title)" +sed -i '/^title: /d' "$d/site/guide/thing.mdx" +must_fail "$d" "missing title" + +d="$(fresh no-description)" +sed -i '/^description: /d' "$d/site/guide/thing.mdx" +must_fail "$d" "missing description" + +d="$(fresh no-icon)" +sed -i '/^icon: /d' "$d/site/guide/thing.mdx" +must_fail "$d" "missing icon" + +d="$(fresh long-description)" +long="$(printf 'x%.0s' $(seq 1 161))" +sed -i "s|^description: .*|description: \"$long\"|" "$d/site/guide/thing.mdx" +must_fail "$d" "161 chars" + +d="$(fresh duplicate-title)" +sed -i 's|^title: "The thing"|title: "Cortex Docs"|' "$d/site/guide/thing.mdx" +must_fail "$d" "duplicates" + +# --- forbidden vocabulary -------------------------------------------------------- +d="$(fresh vendor)" +printf '\nCortex is not Anthropic.\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "competitor: Anthropic" + +d="$(fresh auth-internal)" +printf '\nThe `refresh_token` is rotated.\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "refresh_token" + +d="$(fresh image)" +printf '\n![A picture](/images/thing.png)\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "markdown image" + +d="$(fresh emoji)" +printf '\nShip it '"$(printf '\xf0\x9f\x9a\x80')"'\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "emoji" + +# The card suits are excluded from the emoji range on purpose: the terminal interface +# prints them as row markers, so they are product glyphs inside a quoted string. +d="$(fresh card-suit)" +printf '\nThe status line reads `'"$(printf '\xe2\x99\xa6')"' Thought for 4s`.\n' \ + >> "$d/site/guide/thing.mdx" +out="$(run "$d")" || fail "a card suit is not emoji, got: $out" + +# --- API paths ------------------------------------------------------------------- +# Allowed on the problem pages, as the happy path already proved. Not elsewhere. +d="$(fresh api-path)" +printf '\nCall /v1/conversations to list them.\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "non-API page" + +# A fenced block is not prose, so it is not searched for API paths. The external-link +# rule does still read fences, so the host here has to be an allowed one. +d="$(fresh api-path-fenced)" +printf '\n```bash\ncurl https://api.cortex.foundation/v1/conversations\n```\n' >> "$d/site/guide/thing.mdx" +out="$(run "$d")" || fail "a fenced API path should be allowed, got: $out" + +# --- links ----------------------------------------------------------------------- +d="$(fresh dead-link)" +printf '\nSee [nothing](/guide/absent).\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "has no page" + +# A link to a directory resolves through its index page. +d="$(fresh index-link)" +printf '\nSee [the errors](/problems).\n' >> "$d/site/guide/thing.mdx" +out="$(run "$d")" || fail "/problems should resolve to problems/index, got: $out" + +d="$(fresh external-link)" +printf '\nSee [elsewhere](https://example.com/thing).\n' >> "$d/site/guide/thing.mdx" +must_fail "$d" "allowlist" + +d="$(fresh allowed-external)" +printf '\nSee [the repo](https://github.com/CortexLM/backend).\n' >> "$d/site/guide/thing.mdx" +out="$(run "$d")" || fail "a CortexLM repo link should pass, got: $out" + +# --- body -------------------------------------------------------------------------- +d="$(fresh no-related)" +sed -i '/^## Related$/d' "$d/site/guide/thing.mdx" +must_fail "$d" "Related" + +d="$(fresh thin)" +sed -i '/^The documentation describes/d' "$d/site/guide/thing.mdx" +must_fail "$d" "thin page" + +d="$(fresh unbalanced)" +sed -i 's|^</Steps>$||' "$d/site/guide/thing.mdx" +must_fail "$d" "unbalanced <Steps>" + +d="$(fresh card-no-icon)" +sed -i 's| icon="book"||' "$d/site/index.mdx" +must_fail "$d" "without icon" + +d="$(fresh hub-no-cardgroup)" +sed -i 's|<CardGroup cols={2}>|<div>|; s|</CardGroup>|</div>|' "$d/site/index.mdx" +must_fail "$d" "hub page without a <CardGroup>" + +echo "check-docs-content.test.sh: ok" diff --git a/scripts/tests/check-docs-site.test.sh b/scripts/tests/check-docs-site.test.sh index e3de33d..f40638d 100755 --- a/scripts/tests/check-docs-site.test.sh +++ b/scripts/tests/check-docs-site.test.sh @@ -2,7 +2,8 @@ # Holds scripts/check-docs-site.mjs. No Mintlify CLI: a throwaway tree with a # fake ErrorCode, a fake router, and a couple of MDX files is enough to prove # a matching site passes and that a wrong domain, a missing page, a dead -# navigation entry, or an invented /v1 path fails. +# navigation entry, an image, a leaked auth internal, or an invented /v1 path +# fails. set -euo pipefail root="$(cd "$(dirname "$0")/../.." && pwd)" @@ -20,7 +21,8 @@ seed() { "$dest/crates/cortex-core/src" \ "$dest/crates/cortex-api/src" \ "$dest/packages/api-types/src" \ - "$dest/site/problems" + "$dest/site/problems" \ + "$dest/site/logo" cat > "$dest/crates/cortex-core/src/error.rs" <<'RS' pub const PROBLEM_TYPE_BASE: &str = "https://docs.cortex.foundation/problems"; @@ -41,24 +43,56 @@ TS .route("/conversations", get(list)) .route("/conversations/{id}", get(get).patch(patch)) RS - cat > "$dest/site/docs.json" <<'JSON' + printf '<svg xmlns="http://www.w3.org/2000/svg"></svg>' > "$dest/site/favicon.svg" + printf '<svg xmlns="http://www.w3.org/2000/svg"></svg>' > "$dest/site/logo/light.svg" + printf '<svg xmlns="http://www.w3.org/2000/svg"></svg>' > "$dest/site/logo/dark.svg" + write_docs_json "$dest" '"pages": ["problems/not_found", "problems/internal"]' + for code in not_found internal; do + cat > "$dest/site/problems/${code}.mdx" <<MDX +--- +title: "${code}" +description: "A problem page." +--- + +\`type\` is \`https://docs.cortex.foundation/problems/${code}\`. + +| Method | Path | +| --- | --- | +| \`GET\` | \`/v1/conversations\` | +MDX + done +} + +# A minimal docs.json with the product tabs the checker requires. The first +# argument is the tree; the second is the JSON for the "Errors" group body. +write_docs_json() { + local dest="$1" + local errors_group_body="$2" + local tab_groups="" + for tab in Chat Code Bot CLI Design Security; do + tab_groups="$tab_groups{ \"tab\": \"$tab\", \"icon\": \"star\", \"groups\": [ { \"group\": \"Overview\", \"icon\": \"star\", \"pages\": [\"problems/not_found\"] } ] }," + done + cat > "$dest/site/docs.json" <<JSON { + "theme": "mint", "name": "Cortex", - "logo": { "href": "https://docs.cortex.foundation" }, + "favicon": "/favicon.svg", + "logo": { "light": "/logo/light.svg", "dark": "/logo/dark.svg", "href": "https://docs.cortex.foundation" }, "navbar": { - "links": [ - { "label": "Home", "href": "/" }, - { "label": "Documentation", "href": "/problems/not_found" } - ] + "links": [ { "label": "Website", "href": "https://cortex.foundation" } ], + "primary": { "type": "button", "label": "Open Cortex", "href": "https://cortex.foundation" } }, "navigation": { "tabs": [ + $tab_groups { - "tab": "API", + "tab": "Reference", + "icon": "book", "groups": [ { - "group": "Problems", - "pages": ["problems/not_found", "problems/internal"] + "group": "Errors", + "icon": "triangle-exclamation", + $errors_group_body } ] } @@ -66,19 +100,6 @@ RS } } JSON - for code in not_found internal; do - cat > "$dest/site/problems/${code}.mdx" <<MDX ---- -title: "${code}" ---- - -\`type\` is \`https://docs.cortex.foundation/problems/${code}\`. - -| Method | Path | -| --- | --- | -| \`GET\` | \`/v1/conversations\` | -MDX - done } must_fail() { @@ -88,7 +109,7 @@ must_fail() { if out="$(CORTEX_CHECK_ROOT="$dir/site" node "$script" "$dir" 2>&1)"; then fail "expected failure mentioning ${needle}, got success: ${out}" fi - printf '%s' "$out" | grep -q "$needle" || fail "expected stderr to mention ${needle}, got: ${out}" + printf '%s' "$out" | grep -q -- "$needle" || fail "expected stderr to mention ${needle}, got: ${out}" } # Happy path: matching domain, both codes, documented route exists. @@ -129,42 +150,39 @@ seed "$stale" printf '\nSee https://docs.cortex.sh/problems/not_found\n' >> "$stale/site/problems/not_found.mdx" must_fail "$stale" "docs.cortex.sh" -# Product chrome in the top navbar (Chat | Code | Bot belongs in documentation tabs). -chrome="$tmp/chrome-nav" -seed "$chrome" -cat > "$chrome/site/docs.json" <<'JSON' +# Navigation must be tabs, one per application. +groupsnav="$tmp/groups-nav" +seed "$groupsnav" +cat > "$groupsnav/site/docs.json" <<'JSON' { + "theme": "mint", "name": "Cortex", - "logo": { "href": "https://docs.cortex.foundation" }, - "navbar": { - "links": [ - { "label": "Home", "href": "/" }, - { "label": "Chat", "href": "/chat" }, - { "label": "Code", "href": "/code" }, - { "label": "Bot", "href": "/bot" } - ] + "favicon": "/favicon.svg", + "logo": { "light": "/logo/light.svg", "dark": "/logo/dark.svg", "href": "https://docs.cortex.foundation" }, + "navigation": { + "groups": [ { "group": "Problems", "icon": "list", "pages": ["problems/not_found", "problems/internal"] } ] } } JSON -must_fail "$chrome" "product chrome" +must_fail "$groupsnav" "navigation.tabs" -# Brand-green Install CTA on the navbar. -primary="$tmp/primary-cta" -seed "$primary" -cat > "$primary/site/docs.json" <<'JSON' -{ - "name": "Cortex", - "logo": { "href": "https://docs.cortex.foundation" }, - "navbar": { - "links": [ - { "label": "Home", "href": "/" }, - { "label": "Documentation", "href": "/problems/not_found" } - ], - "primary": { "type": "button", "label": "Install", "href": "/problems/not_found" } - } -} -JSON -must_fail "$primary" "navbar.primary" +# A product tab may not go missing. +notab="$tmp/no-bot-tab" +seed "$notab" +sed -i 's/"tab": "Bot"/"tab": "Agents"/' "$notab/site/docs.json" +must_fail "$notab" '"Bot" tab' + +# Every tab and group carries an icon. +noicon="$tmp/no-icon" +seed "$noicon" +sed -i '0,/"icon": "star",/s//"icon": "",/' "$noicon/site/docs.json" +must_fail "$noicon" "has no icon" + +# The theme is the Mintlify starter theme. +theme="$tmp/theme" +seed "$theme" +sed -i 's/"theme": "mint"/"theme": "willow"/' "$theme/site/docs.json" +must_fail "$theme" 'theme must be "mint"' # Auth / OAuth internals must not ship on the public docs site. authpage="$tmp/auth-page" @@ -173,6 +191,8 @@ mkdir -p "$authpage/site/api" cat > "$authpage/site/api/authentication.mdx" <<'MDX' --- title: "Authentication" +description: "Sign in." +icon: "lock" --- Sign in. MDX @@ -205,63 +225,47 @@ must_fail "$cookie" "cortex_rt" authnav="$tmp/auth-nav" seed "$authnav" -cat > "$authnav/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": "API", - "groups": [ - { "group": "App API", "pages": ["api/overview", "api/authentication", "api/oauth"] } - ] - } - ] - } -} -JSON +write_docs_json "$authnav" '"pages": ["problems/not_found", "problems/internal", "api/authentication", "api/oauth"]' must_fail "$authnav" "api/authentication" +# Images are not allowed: the site uses icons. +img="$tmp/img" +seed "$img" +printf '\n<img src="/logo/light.svg" alt="logo" />\n' >> "$img/site/problems/not_found.mdx" +must_fail "$img" "no images" + +frame="$tmp/frame" +seed "$frame" +printf '\n<Frame><p>x</p></Frame>\n' >> "$frame/site/problems/not_found.mdx" +must_fail "$frame" "no images" + +mdimg="$tmp/md-img" +seed "$mdimg" +printf '\n![alt](/logo/light.svg)\n' >> "$mdimg/site/problems/not_found.mdx" +must_fail "$mdimg" "no images" + +imgfm="$tmp/img-frontmatter" +seed "$imgfm" +sed -i 's|^description: "A problem page."|description: "A problem page."\nimage: "/logo/light.svg"|' "$imgfm/site/problems/not_found.mdx" +must_fail "$imgfm" "no images" + +# Frontmatter: description length and unique titles. +longdesc="$tmp/long-desc" +seed "$longdesc" +long="$(printf 'x%.0s' $(seq 1 170))" +sed -i "s|^description: \"A problem page.\"|description: \"$long\"|" "$longdesc/site/problems/not_found.mdx" +must_fail "$longdesc" "max 160" + +duptitle="$tmp/dup-title" +seed "$duptitle" +sed -i 's|^title: "internal"|title: "not_found"|' "$duptitle/site/problems/internal.mdx" +must_fail "$duptitle" "repeats the title" + # A navigation slug with no MDX page must fail (Mintlify would ship a 404 link). # Nested `{ group, pages }` is included so a one-level walker cannot sneak through. missingnav="$tmp/missing-nav" seed "$missingnav" -cat > "$missingnav/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": "API", - "groups": [ - { - "group": "Public", - "pages": [ - "problems/not_found", - "missing-mintlify-page", - { "group": "Nested", "pages": ["also-missing-mintlify-page"] } - ] - } - ] - } - ] - } -} -JSON +write_docs_json "$missingnav" '"pages": ["problems/not_found", "missing-mintlify-page", { "group": "Nested", "icon": "list", "pages": ["also-missing-mintlify-page"] }]' must_fail "$missingnav" "missing-mintlify-page" must_fail "$missingnav" "also-missing-mintlify-page" @@ -269,97 +273,27 @@ must_fail "$missingnav" "also-missing-mintlify-page" # `pages`. Walking only `pages` would publish a dead group title. missingroot="$tmp/missing-root" seed "$missingroot" -cat > "$missingroot/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": "API", - "groups": [ - { - "group": "Problems", - "root": "missing-root-page", - "pages": ["problems/not_found", "problems/internal"] - } - ] - } - ] - } -} -JSON +write_docs_json "$missingroot" '"root": "missing-root-page", "pages": ["problems/not_found", "problems/internal"]' must_fail "$missingroot" "missing-root-page" # The same group with a root that does exist must pass. goodroot="$tmp/good-root" seed "$goodroot" -cat > "$goodroot/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": "API", - "groups": [ - { - "group": "Problems", - "root": "problems/not_found", - "pages": ["problems/internal"] - } - ] - } - ] - } -} -JSON +write_docs_json "$goodroot" '"root": "problems/not_found", "pages": ["problems/internal"]' out="$(CORTEX_CHECK_ROOT="$goodroot/site" node "$script" "$goodroot" 2>&1)" || fail "a group root backed by an MDX page should pass, got: $out" -# Retired fake-app SVG plates must not appear in public MDX. -frames="$tmp/fake-app-frame" -seed "$frames" -printf '\n<img src="/images/frames/switcher.svg" alt="mock" />\n' >> "$frames/site/problems/not_found.mdx" -must_fail "$frames" "fake-app" +# An internal link inside a page must resolve to an MDX page. +deadlink="$tmp/dead-link" +seed "$deadlink" +printf '\nSee [the missing page](/reference/does-not-exist).\n' >> "$deadlink/site/problems/not_found.mdx" +must_fail "$deadlink" "reference/does-not-exist" # A navbar href with no MDX page must fail even when every `pages` slug exists. missinghref="$tmp/missing-href" seed "$missinghref" -cat > "$missinghref/site/docs.json" <<'JSON' -{ - "name": "Cortex", - "logo": { "href": "https://docs.cortex.foundation" }, - "navbar": { - "links": [ - { "label": "Home", "href": "/" }, - { "label": "Documentation", "href": "/missing-mintlify-page" } - ] - }, - "navigation": { - "tabs": [ - { - "tab": "API", - "groups": [ - { "group": "Problems", "pages": ["problems/not_found", "problems/internal"] } - ] - } - ] - } -} -JSON +sed -i 's|"href": "https://cortex.foundation" }$|"href": "/missing-mintlify-page" }|' "$missinghref/site/docs.json" +sed -i '0,/"label": "Website", "href": "https:\/\/cortex.foundation"/s//"label": "Website", "href": "\/missing-mintlify-page"/' "$missinghref/site/docs.json" must_fail "$missinghref" "missing-mintlify-page" echo "check-docs-site: ok" diff --git a/scripts/tests/docs-ui.test.mjs b/scripts/tests/docs-ui.test.mjs index 57740f7..51d3dd2 100644 --- a/scripts/tests/docs-ui.test.mjs +++ b/scripts/tests/docs-ui.test.mjs @@ -1,45 +1,65 @@ import assert from 'node:assert/strict'; -import { readFileSync } from 'node:fs'; +import { existsSync, readFileSync } from 'node:fs'; const root = new URL('../../', import.meta.url); const config = JSON.parse(readFileSync(new URL('docs.json', root), 'utf8')); -assert.equal(config.theme, 'willow'); -assert.deepEqual(config.navbar.links, [ - { label: 'Home', href: '/' }, - { label: 'Documentation', href: '/getting-started/quickstart' }, -]); -assert.equal(config.navbar.primary, undefined); + +// The site starts from the Mintlify starter kit: the `mint` theme, a favicon, +// a light and a dark logo, a navbar with links and one primary button, and +// contextual options. Icons come from Font Awesome (the starter default), so +// `icons.library` stays unset. +assert.equal(config.theme, 'mint'); +assert.ok(typeof config.favicon === 'string' && existsSync(new URL(config.favicon.replace(/^\//, ''), root))); for (const mode of ['light', 'dark']) { const file = new URL(config.logo[mode].replace(/^\//, ''), root); - assert.equal(readFileSync(file).subarray(0, 8).toString('hex'), '89504e470d0a1a0a'); + assert.ok(existsSync(file), `logo.${mode} must exist`); + assert.ok(readFileSync(file, 'utf8').startsWith('<svg'), `logo.${mode} must be an SVG`); } -assert.equal(config.icons.library, 'lucide'); +assert.equal(config.icons, undefined, 'icons come from Font Awesome, the starter default'); +assert.ok(Array.isArray(config.navbar.links) && config.navbar.links.length > 0); +assert.equal(config.navbar.primary?.type, 'button'); +assert.equal(config.navbar.primary?.label, 'Open Cortex'); +assert.ok(Array.isArray(config.contextual?.options) && config.contextual.options.includes('copy')); -// The sidebar is one flat list of top-level groups. `tabs`, `dropdowns` and -// `products` each render a second-level switcher in the navbar — the app -// dropdown this site deliberately dropped — so a group-only navigation is the -// contract, not a preference. -assert.equal(config.navigation.tabs, undefined); +// Navigation is one tab per application in the navbar, the way a reader picks +// a product on any large documentation site. Every tab and every group has an +// icon; every product tab opens on its hub page. +assert.ok(Array.isArray(config.navigation.tabs), 'navigation must be tabs'); +assert.equal(config.navigation.groups, undefined); assert.equal(config.navigation.dropdowns, undefined); assert.equal(config.navigation.products, undefined); -assert.ok(Array.isArray(config.navigation.groups)); -assert.ok( - config.navigation.groups.every(group => typeof group.group === 'string' && group.icon), - 'every top-level group needs a label and an icon', -); -// One hub per product: the group that opens a product starts at its hub page, -// so the sidebar title and the entry point are the same page. -for (const hub of [ +const tabs = config.navigation.tabs.map((tab) => tab.tab); +assert.deepEqual(tabs, ['Get started', 'Chat', 'Code', 'Bot', 'CLI', 'Design', 'Security', 'Reference']); +for (const tab of config.navigation.tabs) { + assert.ok(tab.icon, `tab "${tab.tab}" needs an icon`); + assert.ok(Array.isArray(tab.groups) && tab.groups.length > 0, `tab "${tab.tab}" needs groups`); + for (const group of tab.groups) { + assert.ok(typeof group.group === 'string' && group.icon, `group "${group.group}" needs a label and an icon`); + assert.ok(Array.isArray(group.pages) && group.pages.length > 0, `group "${group.group}" needs pages`); + } +} +for (const [label, hub] of [ ['Chat', 'chat/index'], ['Code', 'code/index'], ['Bot', 'bot/index'], ['CLI', 'cli/index'], ['Design', 'design/index'], + ['Security', 'security/index'], ]) { - const [label, root] = hub; - const group = config.navigation.groups.find(candidate => candidate.group === label); - assert.ok(group, `navigation must carry a top-level "${label}" group`); - assert.equal(group.root, root, `"${label}" must open ${root}`); + const tab = config.navigation.tabs.find((candidate) => candidate.tab === label); + assert.equal(tab.groups[0].pages[0], hub, `"${label}" must open on ${hub}`); } -assert.deepEqual(config.footer.links.map(group => group.header), ['Products', 'Resources', 'Cortex']); -console.log('docs-ui: native theme, flat hub sidebar, logos, icons and footer passed'); +assert.equal(config.navigation.tabs[0].groups[0].pages[0], 'index', 'Get started opens on the home page'); + +// Global anchors and the footer keep the reader one click from the changelog, +// the status page, and the product. +const anchors = config.navigation.global.anchors.map((anchor) => anchor.href); +assert.ok(anchors.includes('/changelog')); +assert.ok(anchors.includes('https://status.cortex.foundation')); +assert.deepEqual(config.footer.links.map((group) => group.header), ['Products', 'Resources', 'Cortex']); + +// No page ships an image: the site is icons only. +assert.ok(!existsSync(new URL('images', root)), 'the images/ directory must not exist'); +assert.ok(!existsSync(new URL('custom.css', root)), 'custom.css is gone with the old ink CTAs'); + +console.log('docs-ui: starter theme, product tabs, icons, anchors and footer passed'); diff --git a/security/agent.mdx b/security/agent.mdx new file mode 100644 index 0000000..ce70b24 --- /dev/null +++ b/security/agent.mdx @@ -0,0 +1,107 @@ +--- +title: "Cortex Agent runs" +description: "How Cortex Agent gathers evidence by running a change in an isolated runtime, what a run page shows, and why a run is never a pass" +icon: "robot" +--- + +Every other part of a Cortex Security review reads your change. A reader can say "this looks like it would fail on empty input", but it cannot tell you whether it does. Cortex Agent is the part that finds out: it checks the pull request out in an isolated runtime, writes the narrowest program that would demonstrate the claim, runs it, and keeps what came back. + +This page explains what that produces, how to read a run and its artifacts, what the statuses mean, and why a Cortex Agent run never counts as an approval, not even when everything it tried came back clean. It also tells you plainly what a run needs from your deployment, because without an isolated runtime there is nothing to run in and every run is recorded as unavailable. + +## Evidence, not findings + +Cortex Agent does not add findings to a review. It adds evidence, and the review's verdict is still arithmetic over the findings that survived the second pass. See [How a review works](/security/how-a-review-works). + +It also answers a different question from your CI. CI already tells you whether this repository's tests still pass on this commit. The useful question a reviewer has is narrower: does the specific defect somebody suspects actually happen. Cortex Agent replaced an earlier stage that ran the repository's own test command, because that stage was answering the question CI had already answered. + +Evidence comes in two kinds, and the split is not the agent's opinion about its own work. + +| Kind | What it is | +| --- | --- | +| **Bug** | A defect that was reproduced. | +| **Exploration** | Everything else: a suite it ran, a script that established what the code does, or a reproduction that did not reproduce. | + +Which one a step becomes is decided by the exit code of the program the agent wrote, never by what the agent says about it afterwards. It is told to exit `9` when the defect happens and zero when it does not, so a model that would like to report a bug cannot do it by writing a more confident sentence. The run page prints `exit {code}` beside every step. + +## What a run needs + +Two separate things have to be true. + +- The policy switch **Let Cortex Agent run the change in an isolated runtime** has to be on. It is on by default. See [Review policy](/security/review-policy). +- The deployment has to have an isolated runtime for it to use. The hint under the switch is exact: *Needs an isolated runtime on this deployment. Without one the run is recorded as unavailable, which is never a pass.* + +<Warning> +An isolated runtime is off by default on a deployment, so in practice most runs are recorded as unavailable with the sentence *This deployment has no isolated runtime for Cortex Agent to use, so this change was not run.* Do not read a review as having run your code unless a run says it did. +</Warning> + +When code really was run, the summary comment on the pull request carries a line saying so. That line is rendered only in that case, so its absence is meaningful. + +A single program the agent writes gets ten minutes of wall clock by default. + +## Read a run + +<Steps> + <Step title="Start from the pull request"> + Open the review in the app. Its **CORTEX AGENT** section reads either **Evidence collected** or **Nothing was run**, with counts beside it for bugs, explorations and artifacts. + </Step> + <Step title="Open the run"> + Choose **View all artifacts**. That opens the run page, headed **Cortex Agent**, with **Open the pull request** to get back to GitHub and **Back to Cortex Security** to return to the review inbox. + </Step> + <Step title="Read what it did"> + **What Cortex Agent did** lists each step in order, labelled **Bug** or **Exploration**, with its `exit {code}`. An exit of 9 is a reproduced defect. Anything else is an exploration, whatever the step was trying to show. + </Step> + <Step title="Open an artifact"> + **Artifacts** lists the files the run kept. Selecting one shows its media type, its `SHA-256 {hash}` and its contents, with **Copy** to take the text away. + </Step> +</Steps> + +## Artifacts + +Anything a program the agent wrote leaves in the run's artifacts directory is lifted out of the log and kept with a name, a media type, a size, a checksum and a one-clause description of what it is. Path separators are stripped from the name, so an artifact cannot pretend to be a path. + +Artifacts are always shown as text, whatever their media type says, and they are served as data rather than as their own type. That is deliberate: an artifact is output from a program a model wrote, and nothing a browser would execute should be handed to you as something to execute. The media type is read from a fixed list rather than guessed at. + +Three messages you may meet in the viewer: + +| Message | What it means | +| --- | --- | +| *This run kept no files. The harnesses it wrote printed their results rather than writing them out.* | Nothing was saved. The evidence is in the step list instead. | +| *The harness wrote more than was kept. This is the beginning of the file.* | The file was long, so only its start was kept. | +| *This file could not be read.* | The artifact itself is unavailable. | + +## When nothing was run + +A run page headed **Nothing was run** always says why, in one of four sentences. + +| What it says | What happened | +| --- | --- | +| *No model was available to write a harness with, so this change was not run.* | Nothing was available to write the program with. | +| *This deployment has no isolated runtime for Cortex Agent to use, so this change was not run.* | The common one. Nothing on the deployment to run it in. | +| *There was nothing in this change that a program could demonstrate.* | The change had no claim a program could settle, which is the ordinary case for a documentation or styling change. | +| *The isolated runtime could not be reached, so this change was not run.* | Something else went wrong reaching the runtime. | + +Every one of them is followed by the same line: *A run that could not happen is never a pass, and nothing here counts towards the review's verdict.* There is also a shorter version of the same idea for a run that simply had no work: *Cortex Agent checked this change out and found nothing a program could demonstrate.* + +## Run statuses + +| Status | Meaning | +| --- | --- | +| Planning | The run is being planned. | +| Running | A program is running. | +| Completed | The agent ran what it planned. What it found is in the evidence. | +| Failed | The stage itself failed. | +| Unavailable | No runtime, nothing to write the program with, or nothing worth running. Never a pass. | + +An unavailable run cannot claim a bug, an exploration or an artifact, and it cannot exist without a reason attached. That is enforced in storage rather than by convention, so there is no path by which an empty run becomes a quiet success. + +## Who can see a run + +A run page is signed in, and only the account that owns the review can open it. A run belonging to another account is reported as not found rather than as forbidden, so the page cannot be used to work out whether a run id is real. Every account sees only its own reviews. + +## Related + +- [How a review works](/security/how-a-review-works) - the stages a review moves through, and where a run fits. +- [Review policy](/security/review-policy) - the switch that allows a run, and everything else a review consults. +- [Checks and comments](/security/checks) - the summary comment, including the line that appears when code was run. +- [Repository scans](/security/scans) - the other way Cortex Security looks at a repository. +- [Security troubleshooting](/security/troubleshooting) - when a run reads **Nothing was run** and you expected otherwise. diff --git a/security/checks.mdx b/security/checks.mdx new file mode 100644 index 0000000..5c1e300 --- /dev/null +++ b/security/checks.mdx @@ -0,0 +1,124 @@ +--- +title: "Checks and comments" +description: "The Cortex Security check run and its three conclusions, the summary comment, what an inline finding contains, and how to ask for another look" +icon: "circle-check" +--- + +Everything Cortex Security has to say about a pull request lands on the pull request itself: a check run named **Cortex Security**, review comments on the lines the change touched, a summary comment, and a review event. This page is the reference for all four, plus the one thing you have to do in GitHub if you want a red check to actually stop a merge. + +It is the page to read when you are looking at a comment and want to know what each part of it means, when a comment you expected is missing, or when you want another pass over the current head. [How a review works](/security/how-a-review-works) covers the stages behind these outputs and how the verdict is decided; this page covers what you see. + +## The check run + +The check run is created a moment after the pull-request event arrives, once Cortex has split the change up, and it appears together with the eyes reaction that says the review has started. It then sits in progress while the review runs and completes with one of three conclusions. The **Checks** tab in the app explains the same three under the heading **THE CHECK RUN**. + +| Conclusion | What it means | +| --- | --- | +| **Success** | The review finished and nothing that blocks survived verification. There may still be observations to read. | +| **Failure** | Something blocking or major survived verification, and this repository's policy fails the check on it. Whether the pass ran to the end does not change this conclusion. | +| **Neutral** | *The review could not run, or did not finish. The summary says why. This is never an approval — a change nobody reviewed must not report as one.* | + +Under **SEVERITIES** the rule is short: **blocking** and **major** findings fail the check, and **minor** findings and **notes** never do. A check that fails on a note teaches people to click through it. Which severity is serious enough to fail the check is a policy setting of its own, separate from which findings get reported at all, and a **Neutral** conclusion always means the pass did not complete rather than that it found something. The reasons a review ends **Neutral** are listed in [How a review works](/security/how-a-review-works). + +## What lands on a pull request + +Four things, each of which your policy can switch off. + +1. **The check run** named **Cortex Security**. +2. **Inline comments** posted as review comments on the change itself, one thread per finding, on the line. +3. **A summary comment**, up to three blocks plus a footer. +4. **A review event**: changes requested when something blocking survived, or a plain comment otherwise. + +Reactions on the pull request, or on the comment that asked for the review, track the run while it happens. An eyes reaction means the review has started, a thumbs-up means it finished, and a confused reaction means it could not run. There is never a thumbs-up on a review that did not happen, for the same reason there is never a green check run on one. + +## What an inline comment contains + +A finding's thread has five parts, in this order. + +| Part | What it is | +| --- | --- | +| A severity badge | A shield carrying the severity's initial. | +| The title | What the finding is, in one line. For a rule finding this is the rule's own title. | +| The failure mode | How it goes wrong, and the input that reaches it. | +| A committable suggestion | Optional. A concrete replacement you can commit from GitHub. | +| A footer | The category, the weakness class, and how certain the finding is. | + +The weakness class in the footer is a CWE identifier rather than prose, and it is in the footer rather than the title because a reader scanning a pull request wants the failure while a reader triaging one wants to search for `CWE-89`. Expect it to be absent outside security findings: most correctness bugs are not a weakness class, and an invented one would destroy the only property the field has, which is that two runs agree. + +The severity is one of four words, and the app shows each with a one-letter mark: **Blocking** (`B`), **Major** (`M`), **Minor** (`m`), **Note** (`N`). Confidence is one of three phrases, written the way the policy form writes them: **Confirmed in the diff**, **Depends on a caller not shown**, or **Worth checking**. + +<Note> +A committable suggestion is dropped rather than approximated. A suggestion block renders a **Commit suggestion** button, which reads as something that was checked, and one broken suggestion costs the trust of every correct one after it. So a fix that is empty, longer than twelve lines, or that contains a code fence of its own is not rendered at all. +</Note> + +Each comment carries an invisible fingerprint, so the next review over the same line **edits** the existing comment instead of adding a second one. That is the **Edit comments on a new push instead of adding more** setting, on by default. + +## Why a comment you expected is missing + +By default a review posts at most **25** inline comments, worst first, and an owner can set that anywhere from 1 to 100. Beyond the ceiling, three other things keep a comment off a line: the finding was filtered out before it was posted, the second pass rejected it, or **Post the summary only, with no inline comments** is on. The first two are visible in the app on the pull request's own page, under the disclosures for rejected and filtered findings. See [Review policy](/security/review-policy) for the filters and [How a review works](/security/how-a-review-works) for the second pass. + +When the summary-only setting is on, edits to comments already posted still go out. Leaving a stale comment on a line while the summary says something else is worse than either. + +## The summary comment + +The summary is one comment with three blocks. Each block can be **Hidden**, **Shown** or **Folded** independently. + +| Block | Setting | Content | +| --- | --- | --- | +| Headline and counts | **Headline and counts** | The headline sentence and the severity badges. | +| Confidence score | **Confidence score** | A score from 0 to 5 for the pull request, with a sentence beside it. | +| Issues table | **Issues table** | One row per posted finding. Folded by default. | + +Three things about the confidence score are worth knowing before you sort a dashboard by it. It is arithmetic over what survived verification, for the same reason the verdict is: a model asked for a score *and* for findings produces a pair that disagree, and a reader who sees a 5 out of 5 beside a blocking injection learns to trust neither. An incomplete run scores **0** rather than leaving the score out, because omitting it would let a reader supply the optimistic number themselves. And it is computed over every surviving finding rather than only the posted ones, so a low comment ceiling cannot improve the number people sort by. + +The **footer** carries three things: the review number, the short commit hash that was read, and the handle to mention for another look. They go together or not at all, which is what **Hide the footer** switches, because a re-trigger line with no commit beside it invites somebody to re-run a review of they-do-not-know-what. When Cortex Agent actually ran code, the footer carries one more line saying so, and only then. + +**Write the summary into the pull request description** puts the summary in the description instead of posting it as a comment. + +### Diagrams + +A review can include one diagram in the summary, of the kind the change calls for: a sequence diagram for something crossing a service boundary, an entity relation diagram for a migration, a class diagram for new types, and a flow diagram otherwise. The choice is deterministic, and a small change gets none, which is the common case. + +An invalid diagram is omitted rather than rendered. A diagram that does not parse is a red error box in the middle of a review whose findings are fine, and the reader discounts both. Rejected: the wrong declared type, a header with nothing under it, a stray fence, a click or link directive, and anything over sixty lines. + +## Ask for another look + +| How | What happens | +| --- | --- | +| Push a commit | Re-reviews the pull request, unless **Review again on every push** is off. | +| **Review again** in the app | Open the pull request from the inbox and choose it. A toast reads **Review queued**, or **Could not queue the review**. This opens a new review of the current head. | +| Mention the App on GitHub | A bare mention of `@cortex-security-agent`, or a mention followed by the word `review`. The summary comment's footer carries the handle for exactly this. | + +A mention followed by anything else is a **question**, answered as a reply. A question never approves, never requests changes and never creates a check run. A mention inside a quote or a fenced code block is ignored, which is what stops GitHub's reply button from re-triggering a review on every reply. A comment written by a bot never triggers anything, and editing an old comment to add the handle does nothing: only a newly posted comment counts. + +## Make the check required + +A red check is information until GitHub is told to treat it as a gate. From the **Checks** tab, under **REQUIRING IT**: + +<Steps> + <Step title="Copy the workflow"> + Choose **Copy workflow**; the button then reads **Copied**. It copies a workflow that waits for the **Cortex Security** check run, reads check results only, and fails on any conclusion other than success, giving up after fifteen minutes. + </Step> + <Step title="Commit it"> + Add it to the repository as `.github/workflows/cortex-security.yml`. + </Step> + <Step title="Require that job"> + In GitHub branch protection, add that workflow's job to the branch's required status checks. + </Step> +</Steps> + +Until you do the third step, a failing check does not stop a merge. Whether a merge is blocked is GitHub's decision, not a Cortex setting. + +## When a comment is wrong or unwanted + +Put a thumbs-down on it, or resolve the thread. Both are read as a dismissal of that *class* of finding in that repository, and after three of them the class stops being posted there. Anything blocking or major, anything carrying a CWE, and anything filed under security is never silenced this way, however often it is dismissed. [Review policy](/security/review-policy) has the full conditions. + +A finding that points at a line the pull request did not change should not have been posted at all, and that is exactly what the second pass exists to reject. If you see one, the pull request's page in the app shows what the verifier rejected on that review. + +## Related + +- [How a review works](/security/how-a-review-works) - the stages, the second pass, and the verdict arithmetic behind these conclusions. +- [Review policy](/security/review-policy) - every setting that decides what is posted and how hard it lands. +- [Security quickstart](/security/quickstart) - install the App and read a first review end to end. +- [Cortex Agent runs](/security/agent) - the evidence behind the footer line that says code was run. +- [Security troubleshooting](/security/troubleshooting) - no check run, a green check you expected to be red, or comments that never arrived. diff --git a/security/how-a-review-works.mdx b/security/how-a-review-works.mdx new file mode 100644 index 0000000..b55eb25 --- /dev/null +++ b/security/how-a-review-works.mdx @@ -0,0 +1,171 @@ +--- +title: "How a review works" +description: "The stages a review moves through, the second pass that checks every finding, and why the verdict is arithmetic rather than an opinion" +icon: "diagram-project" +--- + +A Cortex Security review is one pass over one pull request, not a conversation. It starts from a GitHub event, moves through a fixed set of stages, checks every candidate finding a second time, and publishes what survived. The result is stored with the status that pass earned, so a review that could not run is recorded as failed rather than as an approval. + +This page follows that pass from the event to the check run. Read it when you want to know why a finding appeared, why one you expected did not, or what a **Neutral** check run is telling you. For the anatomy of what lands on the pull request, see [Checks and comments](/security/checks); for the settings each stage consults, see [Review policy](/security/review-policy). + +## What starts a review + +| Trigger | Behaviour | +| --- | --- | +| A pull request is opened | The default. Every pull request that passes your filters is reviewed. | +| A commit is pushed to an open pull request | On by default. Switch **Review again on every push** off and the review stays the review of the pull request as opened. | +| Somebody mentions the App in a pull-request comment | Always works, even when reviews are set to happen only when asked. | +| **Review again** in the app | Opens a new review of the current head. | + +Draft pull requests are not reviewed by default. A mention overrides the settings whose job is to keep the reviewer quiet, such as a draft or a policy of reviewing only when asked. It does not override scope filters: an excluded branch stays excluded, and the reply says which setting declined. + +## The stages a review moves through + +While a review is in flight the app shows one line of progress. These are the words it uses, in order: **Queued**, **Reading the change**, **Summarising each file**, `Reviewing file X of Y` counting up through the files, **Verifying findings**, **Posting the review**, and finally **Done**. A review that gave up says **Could not review**, and a stage the app does not recognise shows the single word **Working** rather than nothing at all. + +In product terms, this is what sits behind those words. + +<Steps> + <Step title="The event arrives"> + The App receives the pull-request event. A delivery that is not signed is refused. + </Step> + <Step title="The change is split up"> + One piece per hunk or declaration. This is the point at which the check run appears, along with a reaction on the pull request saying the review has started. + </Step> + <Step title="Each piece is summarised"> + A short description of every piece, so the reviewer of one file knows what the others do. + </Step> + <Step title="The repository is indexed"> + Cortex reads the pull request's head tree, not just the diff, so it can answer "who calls this from a file the change did not touch". That is what makes a finding like "this function stopped accepting an empty value, and its caller in another file has always relied on it" expressible at all. The nearest files to the change are indexed first, up to a budget. The index is heuristic and line-oriented: a missed link costs context, and a spurious one costs an irrelevant caller being shown. + </Step> + <Step title="The change is reviewed"> + A file at a time, then bug theories are tested against it, then the deterministic checks run. See the layers below. + </Step> + <Step title="Every finding is verified"> + A separate second pass, described below, decides which candidates reach GitHub. + </Step> + <Step title="The change may be run"> + Where the deployment has an isolated runtime, Cortex Agent can run the change to gather evidence. It is skipped when there is nothing to run. The setting for it is on by default, but the runtime it needs is absent on most deployments, so in practice the run is recorded as unavailable, with `This deployment has no isolated runtime for Cortex Agent to use, so this change was not run.` A run that could not happen is never a pass. See [Cortex Agent runs](/security/agent). + </Step> + <Step title="The review is published"> + Inline comments, the summary comment, the review event and the check run's conclusion. + </Step> +</Steps> + +Each stage records what it did, so a review survives the process that started it, and a redelivered event cannot start a second review of the same change. + +## What looks at your change + +Five things can produce a finding. All of them produce the same kind of finding, all of them go through the same second pass, and duplicates between them are collapsed into one comment. The pull-request page records which layer each finding came from. + +| Layer | What it sees | +| --- | --- | +| The reviewer | One file at a time, plus the summaries of related files. | +| Bug theories | The diff plus the indexed repository's reach. Each theory is one agent, told one theory, what would count as proof of it, and what would count as it being absent. Only theories whose category your policy still allows are planned, so switching a criterion off removes its theories from the plan rather than filtering their findings afterwards. At most six run per review, four at a time. | +| Rules | The changed lines only, matched by shape. No model is involved. | +| Advisories | The dependency manifests the change touches. No model is involved. | +| Cortex Agent | The change, actually running. It produces evidence rather than findings. | + +The rules and the advisories are the two layers with nothing to switch on: they cost nothing to run, so they always run. A raised severity floor cannot silence either of them when the finding is filed under security, on the reasoning that somebody who raised their floor asked for a quieter reviewer rather than to stop being told about injection. A security finding the reviewer itself wrote is filtered normally, which keeps the exemption predictable. When a rule and the reviewer catch the same weakness on the same line, you get the reviewer's prose with the rule's identity and severity, so the comment that names the variable is the one that cannot be silenced. + +Rule findings are titled plainly, and the title is what you read at the top of the comment: **SQL query built by string concatenation**, **Certificate verification switched off**, **A live credential written into the source**. Eleven such rules ship, they are Cortex's own, and each body names the fix rather than only the problem. Because they match on shape, with exclusions so that the fix is not reported as the bug, a rule can miss and never needs a model. + +Advisory findings are the ones no reviewer could make by reading the diff: the line is correct, the code using it is correct, and the defect is in the published package. They come from a built-in table of published advisories for npm, PyPI, Cargo and Go packages, so nothing is fetched while a review runs and two runs of the same review agree. Each advisory in that table carries its published identifier, a `CVE-…` or a `RUSTSEC-…` id, which is what lets you go and read the original advisory rather than take the finding's word for it. + +A finding is made only when the change touches the manifest, and only when **every** version your declaration permits is affected. A range that already allows the fixed version is not a finding, which is the rule you can check against your own lockfile and agree with. Where the comment lands follows what you did to the manifest: + +| What the change does | What is reported | +| --- | --- | +| Adds or edits the dependency's own line | An inline finding on that line | +| Edits the manifest somewhere else | A file-level finding | +| Does not touch the manifest | Nothing | + +At most twenty advisory findings are made per review, reading at most 512 KB from any one manifest. + +## What is never reviewed + +Generated and vendored content is recorded as touched and never reviewed: lockfiles, bundles, vendored trees. If every changed file falls in that set, the review ends as failed, with the reason *Every changed file is generated or vendored, so there was nothing to review.* It does not end as an approval, because nobody looked. + +## The second pass + +Every candidate finding is checked again by a separate pass, which is asked a closed question about it: is this specific claim supported by this specific text. That is a narrower question than "what is wrong with this file", and two of its four rejections need no model at all. + +| Why a finding is rejected | What it means | +| --- | --- | +| The path is not in this pull request | The finding pointed somewhere this change does not go. | +| The line was not changed here | The path is in the pull request, but that line is not part of the change. | +| The claim is not supported | The source shown does not back up what the finding says. This is the case that catches a confident sentence about code that does not do that. | +| Another finding already says this | A duplicate. | + +Rejections are counted rather than quietly dropped. Open a review in the app and you get a disclosure reading **N findings the verifier rejected**, each carrying a `Not posted — {reason}.` line, so a second pass that rejects everything is visible instead of merely quiet. When nothing survives at all, the review says so: *Nothing survived verification. Every candidate finding either pointed at a line this pull request did not change or could not be supported by the change itself.* + +## Posted, discarded, filtered out + +A finding ends in one of three states, and the app keeps them apart on purpose. + +| State | Meaning | +| --- | --- | +| Posted | It reached GitHub. | +| Discarded | The second pass rejected it. The finding was wrong. | +| Filtered out | Your policy, or what this repository has dismissed before, did not want to hear it. Nobody said it was wrong. | + +The filtered ones appear under **N findings your review policy filtered out**, each with a reason: the finding was below the severity floor, below the confidence floor, filed under a criterion that is switched off, or silenced because this repository has dismissed that class of finding before. + +The first three are settings on the policy form. The fourth is not a setting: after the same class of finding has been dismissed three times, this repository stops being sent it, and there is no screen listing what has been silenced. Anything blocking or major, anything carrying a CWE, and anything filed under security is never silenced this way, however often it is dismissed. See [Review policy](/security/review-policy). + +## The verdict is arithmetic + +What the review concludes is derived from what survived verification, so it can never disagree with the findings printed beside it. A model is never asked for the verdict. + +| What survived | Run complete? | What is posted on the pull request | Check run | +| --- | --- | --- | --- | +| Any blocking or major finding | Either | Changes requested | **Failure** | +| Only minor findings or notes | Yes | A comment | **Success** | +| Nothing | Yes | No review event | **Success** | +| Anything | No | A comment | **Neutral** | +| The review failed | — | No review event | **Neutral** | + +"Complete" means every assigned file came back readable **and** the second pass ran. Without that condition, a review whose file stage died halfway would have no findings, and "no findings" would read as "approved". + +The first row is what a repository does before anybody changes a setting, and it is the one row a setting moves. **On a blocking finding** bends its last two columns together rather than just the check, so read them as a pair. + +<Warning> +No row in that table is an approval. A clean review reports **Success** and stops there: Cortex Security does not approve a pull request, and the setting a reader would expect to find for it is not offered. The policy form states it as fact under **Human approval required**, because *Cortex never approves a pull request automatically. Quality findings remain for a person to review.* +</Warning> + +Two policy settings bend that pair of columns. **On a blocking finding** decides whether a blocking finding only comments, requests changes, or requests changes and fails the check, and each of the three moves both columns: on the first, the review event stays a plain comment and the check never reports **Failure** at all; on the second, changes are requested but the check still reports **Success**; only the third, the default, gives you the row above. **Fail the check run at** decides which severity is serious enough to fail it, separately from which findings get reported, so you can comment on everything and still only block on the serious. Whether a failing check blocks a merge is GitHub branch protection rather than a Cortex setting: a reviewer that could block a merge on its own authority would be one nobody could switch off in a hurry. + +## A failed review stays failed + +When a review could not run, the row in the inbox reads **Not reviewed** and carries one sentence explaining which of seven things happened. Those sentences are the whole explanation. They are not platform error codes, and there is no error-code page to look them up in. + +| What went wrong | What to do | +| --- | --- | +| Every changed file was generated or vendored | Nothing in the change was reviewable. This is a failure, not an approval. | +| No model was available to review with | Choose **Review again**, and ask whoever runs the deployment if it keeps happening. | +| The deployment's model service is not configured | Ask whoever runs the deployment. Nothing you can change in the policy will fix this one. | +| The GitHub App is not configured on this deployment | An operator has to supply its credentials before anything is reviewed. | +| The change could not be read from GitHub | Ask for another look once GitHub is answering again. | +| The installation is suspended on GitHub | Unsuspend it from the app's settings page. See [Installation and repositories](/security/repositories). | +| The review did not finish | Choose **Review again**. | +| Anything else | The row falls back to *Cortex Security could not review this change.* | + +On the pull request itself the check run concludes **Neutral**, and the app's verdict card says *No verdict was reached for this commit, so the check is not an approval.* + +## Skipped is not failed + +A pull request your policy declined also reads **Not reviewed** in the inbox. The pill is the same as a failed review's, and the difference is in the reason line on the row, so do not read the pill alone. Each reason names the setting you would go and change: that it is a draft and *this repository does not review drafts*, that reviews are switched off or happen only when asked, that a later push does not start a new review here, that the base branch or the author is not reviewed, that a required label is absent or a label suppresses review, or that the change is larger than the file limit. Anything else falls back to *This repository's review policy excludes it.* [Security troubleshooting](/security/troubleshooting) works through them symptom by symptom. + +## A pull request cannot talk the reviewer into anything + +A change can contain a comment shaped like an instruction to the reviewer, written by somebody who knows a bot reads it. Every piece of the change crosses a trust boundary before it reaches the reviewer, the second pass or the summariser, with Cortex's own delimiters neutralised inside it. It is handled the way a web page is handled: as text to be read, not as instructions to be followed. + +The same principle governs the settings a repository carries in its own files. A repository can keep instructions and rules on the branch under review, and they can make a review stricter or better informed. They cannot exclude a path, raise a threshold or switch the review off, because the author of a pull request would then have a say over the scrutiny it receives. A refused key is reported back in the review's summary, so a setting quietly dropped and a setting never read do not look the same. + +## Related + +- [Checks and comments](/security/checks) - the check run, the summary comment, and what an inline finding looks like. +- [Review policy](/security/review-policy) - every setting the stages above consult. +- [Cortex Agent runs](/security/agent) - the layer that runs the change instead of reading it. +- [Repository scans](/security/scans) - the other question: what is wrong in this tree, rather than what this change introduced. +- [Security troubleshooting](/security/troubleshooting) - symptom by symptom, when a review does not do what you expected. diff --git a/security/index.mdx b/security/index.mdx new file mode 100644 index 0000000..10bfe64 --- /dev/null +++ b/security/index.mdx @@ -0,0 +1,99 @@ +--- +title: "Cortex Security" +description: "GitHub pull-request review that reads the change in the repository, posts a check run, and never turns a failed review green" +icon: "shield-halved" +--- + +Cortex Security reviews GitHub pull requests where they already are. You install its GitHub App on the repositories you want reviewed, and each pull request opened in them gets a review: inline comments on the lines, a summary comment, and a check run named **Cortex Security**. The product page says it in one line: *GitHub pull-request review without pasting a diff. The change stays in the repository; Cortex reads it there.* + +Security is part of Cortex Code rather than a separate application, so you reach it from inside Code and sign in once for both. This page is the map of the Security tab: what the product guarantees, where each page takes you, and how it differs from the other ways Cortex can look at a repository. + +## What Cortex Security guarantees + +Three commitments shape every surface below, and they are worth reading before the feature list because they explain the shape of everything else. + +| Commitment | What it means for you | +| --- | --- | +| A review that could not run is recorded as failed, never as an approval | "We could not look" and "we looked and it is fine" are opposite answers. A check run that cannot tell them apart is worse than no check at all, so a review that fails reports **Failure** or **Neutral** with a reason, never **Success**. | +| A finding the second pass rejects never reaches GitHub | Every candidate finding is checked a second time against the change itself. Rejections are counted and shown to you as discarded rather than quietly dropped. | +| A person approves, not Cortex | Cortex Security never approves a pull request on your behalf. The policy page states it as fact: **Human approval required**, because *Cortex never approves a pull request automatically.* There is no setting that changes this. | + +<Note> +The merge gate is GitHub's, not Cortex's. Whether a failing **Cortex Security** check blocks a merge depends on whether you made it a required status check in GitHub branch protection. See [Checks and comments](/security/checks). +</Note> + +## Start here + +<CardGroup cols={2}> + <Card title="Security quickstart" icon="rocket" href="/security/quickstart"> + Install the GitHub App, enable a repository, and read your first review end to end. + </Card> + <Card title="How a review works" icon="diagram-project" href="/security/how-a-review-works"> + The stages a review moves through, the second pass, and why the verdict is arithmetic. + </Card> +</CardGroup> + +## Reviews and scans + +<CardGroup cols={2}> + <Card title="Checks and comments" icon="circle-check" href="/security/checks"> + The check run and its three conclusions, the summary comment, inline findings, and re-running a review. + </Card> + <Card title="Review policy" icon="scale-balanced" href="/security/review-policy"> + When to review, what to look at, what to report, and how hard a finding lands. + </Card> + <Card title="Repository scans" icon="magnifying-glass" href="/security/scans"> + On-demand and weekly scans of a repository you own, and what you can do with a finding. + </Card> + <Card title="Cortex Agent runs" icon="robot" href="/security/agent"> + Evidence gathered by running the change in an isolated runtime, and why a run is never a pass. + </Card> +</CardGroup> + +## Configure + +<CardGroup cols={2}> + <Card title="Installation and repositories" icon="github" href="/security/repositories"> + The installation, the repositories list, what the App asks for, and how to stop reviews. + </Card> + <Card title="Security troubleshooting" icon="life-ring" href="/security/troubleshooting"> + No check run, a review stuck, comments missing, or a finding that looks wrong. + </Card> +</CardGroup> + +## How a review behaves + +| Behaviour | Why it works this way | +| --- | --- | +| One pass over the change | A review is a pass, not a conversation. Ask for another look and you get another pass over the current head. | +| Failed stays failed | The result is stored with the status the pass earned. A red review is not turned green so a dashboard can look finished. | +| Nothing is pasted | Pasting a patch into an assistant is how secrets and context leak. This surface deliberately has no such box, which is why the older paste-a-diff page was retired. | +| The policy belongs to the owner | The review policy is set in the app, for the installation. Someone opening a pull request cannot reduce the scrutiny it receives. | + +## Three things called security + +The word does a lot of work across Cortex, so keep these apart. + +| Thing | What it is | +| --- | --- | +| [cortex.foundation/security](https://cortex.foundation/security) | The public product page for Cortex Security. | +| The review inbox, inside Cortex Code | Every pull request Cortex Security has seen, what it found, and the evidence behind it. | +| [Security and privacy](/reference/security-and-privacy) | How Cortex handles your data. A different subject entirely. | + +## How it fits with the other products + +Three GitHub-adjacent things exist, and reaching for the wrong one is the most common mistake. + +- The **Cortex Security GitHub App** reviews pull requests in place. It is installed from the Security surfaces and described in [Installation and repositories](/security/repositories). +- **Connect GitHub** in Cortex Code is a separate connection, used for Code sessions. Neither install implies the other. See [Connect GitHub](/code/github). +- The **Cortex CLI** can review a diff from within your own pipeline, which is a headless Code run rather than the Security App. Use whichever fits, or both. See [Headless and one-shot runs](/cli/headless). + +A scan finding that comes with a suggested patch hands off into a Code session for you to read; nothing is applied for you. That is the seam between the two products: Security decides what is wrong, Code is where a change gets made. + +## Related + +- [Security quickstart](/security/quickstart) - from nothing to a first reviewed pull request. +- [How a review works](/security/how-a-review-works) - the stages, the verifier, the verdict. +- [Checks and comments](/security/checks) - what lands on the pull request. +- [Pull-request review](/code/security) - the same product, seen from the Cortex Code tab. +- [CI cookbook](/cli/ci) - reviewing a diff from your own pipeline instead. diff --git a/security/overview.mdx b/security/overview.mdx deleted file mode 100644 index ca25058..0000000 --- a/security/overview.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Security and privacy" -description: "What Cortex stores, what it never stores, which cookies run, where your code executes, and how to export or delete your data." -image: "/images/banners/security.png" -keywords: ["privacy", "data", "cookies", "storage", "export", "delete"] ---- - -This page is about **how Cortex handles your data and where code runs**. It is not a status page, and it is not the [Cortex Security](/code/security) product that reviews pull requests. - -## Cookies and consent - -Necessary cookies always run: session, language, and your cookie preference. Optional analytics stay off until you allow them, and a **Global Privacy Control** signal keeps them off. Nothing in the current build loads an optional tracker; the preference is recorded so a future one cannot fire without it. - -<Frame caption="The consent banner on first visit. Necessary only is a complete choice."> - <img src="/images/product/privacy-cookie-banner.png" alt="Cookies on this site — Necessary only or Allow optional" /> -</Frame> - -## What Cortex stores - -From **Settings → Data & privacy**, in the product's own words: your account details, conversations and attachments while history is on, saved memories, and billing records. **The content of connected apps is never stored** — Cortex reads it at question time, then discards it. - -<Frame caption="Settings → Data & privacy: chat history, model improvement (off by default), cookies, and optional analytics."> - <img src="/images/product/settings-data-privacy.png" alt="Data & privacy settings — Save chat history, Improve the model, Necessary cookies, Optional analytics" /> -</Frame> - -| Control | Default | What it means | -| --- | --- | --- | -| **Save chat history** | On | Conversations are kept in your account for any device. Off means new chats disappear when you close them. | -| **Improve the model** | Off | Only when on may a sample of your conversations be reviewed to train future models. | -| **Memory** | — | Standing preferences and facts you share, reviewable and deletable one by one. See [Memory](/chat/memory). | -| **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. | - -## 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. - -Connected apps are scoped explicitly. Under **Customize → Connectors** you choose whether each connection is available to **Cortex Chat**, **Cortex Bot**, or both; Bot never inherits a tool you did not assign to it. You stay signed in with the provider — Cortex never sees your passwords. - -## What each product can reach - -| Product | What it reads | What it can change | -| --- | --- | --- | -| **Chat** | Files you attach, connected apps enabled for Chat, pages its web tools fetch | Nothing outside your own account and its Library | -| **Code** | The one repository attached to the session | Files in that repository, inside the session's guest | -| **Bot** | Its own computer, and connected apps enabled for Bot | Its desktop and files, plus connected-app changes — parked behind [Approvals](/bot/approvals) | -| **Cortex Security** | The pull request under review, read in place | Nothing. It posts a check run. | - -Chat cannot see a repository, a Code session cannot reach a bot's desktop, and a bot cannot read a Code session's files. The products do not share a working surface — see [Where code runs](#where-code-runs). - -## Where code runs - -| Surface | Where code runs | What it can see | -| --- | --- | --- | -| Chat's Python tool | A small, untrusted snippet sandbox | The snippet only — no workspace, no repository | -| Code Cloud | An isolated Cloud guest, headless | The repository prepared for that session | -| Code on This PC or SSH | Your machine or your host, from the desktop app or CLI | The project directory you chose | -| Bot computer | An isolated Cloud guest **with** a desktop and a shell | That guest's desktop, browser, and files | -| Cortex Security | Reads the pull request in place on GitHub | The diff under review — nothing is pasted into a composer | - -Do not mix them up. Chat Python cannot see a Code repository, and a Code session cannot reach a Bot's desktop. - -Consequential steps ask first. In Bot, dangerous computer actions and connected-app changes park behind [Allow / Deny / Always](/bot/approvals). In the CLI, every session runs under an approval policy and a sandbox, and the agent asks before it does anything consequential — see [Modes and permissions](/cli/modes-and-permissions). - -<Frame caption="The CLI asking before it runs an install: run once, always allow in this project, edit the command, or decline."> - <img src="/images/cli/runtime/40x12/permission-prompt.png" alt="Cortex CLI approval prompt rendered in a 40 by 12 terminal" /> -</Frame> - -## Errors never name a vendor - -User-facing error text names a Cortex surface, never a subprocessor. The CLI's outage message is deliberately just *The coding service is temporarily unavailable*. Problem documents carry a stable `code` and a `request_id` you can quote when reporting an issue — see [Errors](/api/errors). - -## Cortex Security (pull requests) - -GitHub App review of pull requests is a **product**, at `/code/security` in the app and documented under [Cortex Security](/code/security). The public link `cortex.foundation/security` is that product's page, not this article. - -## What this page does not claim - -Cortex does not claim SOC 2, GDPR certification, or HIPAA compliance in product copy, and neither does this site. Legal documents live at [cortex.foundation/privacy](https://cortex.foundation/privacy), [cortex.foundation/terms](https://cortex.foundation/terms), and [cortex.foundation/ai-disclosures](https://cortex.foundation/ai-disclosures). - -The controls above are what the product actually does — what it stores, what it never stores, and where each surface runs. Where a certification would be needed, the honest answer today is that there is no claim to read, and this page will not invent one. If that changes, it will be announced where the rest of Cortex is: the [changelog](/changelog) and [cortex.foundation](https://cortex.foundation). - -## Related - -- [Accounts](/getting-started/accounts) — what a signed-in account holds. -- [Settings](/getting-started/settings) — the Data & privacy controls in one place. -- [Approvals](/bot/approvals) — how a bot asks before consequential steps. -- [Modes and permissions](/cli/modes-and-permissions) — the CLI's sandbox and approval policy. -- [Errors](/api/errors) — why user-facing text never names a vendor. diff --git a/security/quickstart.mdx b/security/quickstart.mdx new file mode 100644 index 0000000..2ee7c28 --- /dev/null +++ b/security/quickstart.mdx @@ -0,0 +1,106 @@ +--- +title: "Security quickstart" +description: "Install the Cortex Security GitHub App on a repository, open a pull request, and read the check run and summary comment it posts" +icon: "rocket" +--- + +This walk-through takes you from nothing to a reviewed pull request. You need a Cortex account that is not a guest, and a GitHub repository you can install an app on. Everything happens on GitHub.com; the App is installed there, and the review is posted there. + +You will open Security inside Cortex Code, install the GitHub App, enable one repository, open a pull request, and read the four things Cortex Security posts back. The last step, making the check required, is optional and is the one that turns a review into a gate. + +## Your first review + +<Steps> + <Step title="Open Security"> + Sign in with your Cortex account at [cortex.foundation](https://cortex.foundation) and open **Cortex Code**. Security is a mode inside Code rather than a separate product, so there is no row for it in the product switcher. + + Open the Code command palette and choose **Security**. That lands you on the review inbox, headed **Security**, which describes itself as *every pull request Cortex Security has seen, what it found, and the evidence behind it.* + + If the inbox says **Cortex Security is not configured on this deployment**, stop here: this deployment has no GitHub App credentials, so nothing can be installed until an operator supplies them. Choose **Installation details** to see what is missing. + </Step> + <Step title="Install the GitHub App"> + Open the **App** tab. Before an installation exists it reads **Install Cortex Security on GitHub**, with the body *Choose the repositories it can see. Cortex Security asks for read access to code, and write access to pull requests and checks — enough to post a review and report a check run, and nothing else.* + + Choose **Install on GitHub**. GitHub asks which repositories the App may see; pick all of them or a short list, and confirm. GitHub sends you back to the **App** tab, which claims the new installation and confirms it against GitHub before storing it. A toast reads **GitHub connected** on success, or **Could not connect GitHub** if the claim failed. + + This is not the same connection as **Connect GitHub** in Cortex Code. The two coexist and neither implies the other. + </Step> + <Step title="Enable a repository"> + Under **REPOSITORIES**, switch on the repository you want reviewed. The switch is labelled `Review pull requests in {name}`. A repository that is off gets no review, no comment and no check run at all, so nothing appears on its pull requests. + + Under **CONNECTION** the state reads **Connected**, and **Add or remove repositories on GitHub** takes you back to GitHub to change the list. + + Optionally switch on **Review new repositories automatically**: *When a repository is added to the installation later, start reviewing its pull requests without asking. Off means it arrives switched off and you enable it here.* + </Step> + <Step title="Open a pull request"> + Open an ordinary pull request in the repository you just enabled. A draft is **not** reviewed by default, so either mark it ready or ask for a review by mentioning the App in a comment. + + Within moments the pull request picks up an eyes reaction, meaning the review has started, and a check run named **Cortex Security** appears in progress. A thumbs-up reaction is added when the review finishes; a confused reaction means it could not run. There is never a thumbs-up on a review that did not happen. + </Step> + <Step title="Read the check run"> + The check run is created as soon as the event arrives, moves to in progress while the review runs, and completes with one of three conclusions. + + | Conclusion | What it means | + | --- | --- | + | **Success** | The review finished and nothing that blocks survived verification. There may still be observations to read. | + | **Failure** | Something blocking or major survived verification, so this check fails. Whether the pass ran to the end does not change that conclusion. | + | **Neutral** | *The review could not run, or did not finish. The summary says why. This is never an approval — a change nobody reviewed must not report as one.* | + + Blocking and major findings fail the check. Minor findings and notes never do. + </Step> + <Step title="Read the comments"> + Alongside the check run you get up to three more things, each of which your policy can switch off. + + - **Inline comments**, one thread per finding, on the line. A thread carries a severity badge, the finding's title, the failure mode with the input that reaches it, sometimes a committable suggestion, and a footer naming the category, the weakness class and how certain the finding is. + - **A summary comment**, with a headline and counts, a confidence score from 0 to 5 for the pull request, and an issues table that is folded by default. Its footer carries the review number, the commit that was read, and the handle to mention for another look. + - **A review event**: changes requested when something blocking survived, or a plain comment otherwise. + </Step> + <Step title="Read the row in the inbox"> + Back in the inbox, under **PULL REQUESTS**, your pull request now has a row with the status the pass earned: **No findings**, or *N* **to read** when there are findings that do not block, or **1 blocking finding**, or **Not reviewed**. + + Open the row for the whole picture: how many files were reviewed, the short commit, the findings that were posted, the ones the verifier rejected, and the ones your policy filtered out. + </Step> + <Step title="Optional: make the check required"> + Open the **Checks** tab. It explains the check run, the severities, and under **REQUIRING IT** offers **Copy workflow** (the button then reads **Copied**), which copies a workflow that waits for the **Cortex Security** check and fails on any conclusion other than success, with a fifteen-minute deadline. + + Commit it as `.github/workflows/cortex-security.yml`, then add that job to the branch's required status checks in GitHub branch protection. Until you do, a red check is information rather than a gate: whether a merge is blocked is GitHub's decision, not a Cortex setting. + </Step> +</Steps> + +## Ask for another look + +Pushing a new commit re-reviews the pull request, unless **Review again on every push** has been switched off. Two other ways exist: + +- In the app, open the pull request from the inbox and choose **Review again**. A toast reads **Review queued**, or **Could not queue the review**. This opens a new review of the current head. +- On GitHub, post a comment mentioning the App: a bare mention of `@cortex-security-agent`, or a mention followed by the word `review`. The summary comment's footer carries the handle for exactly this. + +A mention followed by anything else is treated as a **question** and answered as a reply. A question never approves, never requests changes and never creates a check run. A mention inside a quote or a fenced code block is ignored, a comment written by a bot never triggers anything, and editing an old comment to add the handle does nothing; only a new comment counts. + +## If nothing has appeared yet + +The inbox has three different empty states, and they mean different things. + +| What it says | What to do | +| --- | --- | +| **Cortex Security is not configured on this deployment** | Nothing can be installed here until an operator supplies the GitHub App credentials. **Installation details** explains what is missing. | +| **Cortex Security is not connected yet** | The App is available but not installed. Choose **Install the GitHub App**, or read **How the check appears** first. | +| **No pull requests yet** | *Cortex Security is connected and watching. The next pull request opened in an enabled repository will appear here while it is being reviewed.* Check the repository is switched on under **Manage repositories**. | + +## What this quickstart deliberately leaves out + +<Warning> +Cortex Security does not approve pull requests. The policy page states **Human approval required**, and there is no toggle to change that: *Cortex never approves a pull request automatically. Quality findings remain for a person to review.* +</Warning> + +- **Security lives inside Cortex Code.** You reach it through the Code command palette entry **Security**, which is the palette's own shortcut rather than one of Security's. +- **A review reads your change; it does not run it.** Running the change to gather evidence is the job of Cortex Agent, and it needs an isolated runtime on your deployment, which is off by default. See [Cortex Agent runs](/security/agent). +- **General code review is off to begin with.** Out of the box a finding has to be a security, correctness, API contract, test or performance problem. Ordinary code-review opinions are a separate layer, off by default per installation, switched on with **Enable general code review** in [Review policy](/security/review-policy). +- **GitHub.com only.** GitHub Enterprise Server is not available yet. + +## Related + +- [How a review works](/security/how-a-review-works) - the stages, the second pass, and how the verdict is decided. +- [Checks and comments](/security/checks) - the check run and everything that lands on the pull request. +- [Installation and repositories](/security/repositories) - what the App asks for, and how to stop reviews. +- [Review policy](/security/review-policy) - when to review, what to report, how hard it lands. +- [Security troubleshooting](/security/troubleshooting) - when no check run appears at all. diff --git a/security/repositories.mdx b/security/repositories.mdx new file mode 100644 index 0000000..3b33954 --- /dev/null +++ b/security/repositories.mdx @@ -0,0 +1,103 @@ +--- +title: "Installation and repositories" +description: "The Cortex Security GitHub App: what it asks for, which repositories it reviews, Security mode, and the four ways to stop reviews" +icon: "github" +--- + +Cortex Security reviews pull requests through a GitHub App that you install on the repositories you choose. This page is about that installation: what the App asks GitHub for and why, how the repositories list works, where the review policy lives, what Security mode adds, and how to stop reviews at four different levels without guessing which one you want. + +For the walk-through that gets you from nothing to a first reviewed pull request, read the [Security quickstart](/security/quickstart) instead. Everything here is the reference behind it, on the **App** tab of Cortex Security. + +## Two GitHub connections, and neither implies the other + +This is the single most common confusion, and the install page carries an inline explainer about exactly it. Three separate things touch GitHub, and reaching for the wrong one is the usual cause of "why is nothing being reviewed". + +| Thing | What it does | +| --- | --- | +| The **Cortex Security GitHub App** | Reviews pull requests in place, posts comments and reports a check run. Installed from the **App** tab. | +| **Connect GitHub** in Cortex Code | Gives Cortex Code access to your repositories for sessions. A separate connection. See [Connect GitHub](/code/github). | +| The **Cortex CLI** in your own pipeline | Runs a review as a headless Cortex Code run, from your CI. Not this App. See [CI cookbook](/cli/ci). | + +The two connections coexist happily, and installing one does not install the other. Use whichever fits, or both. + +## Installing and claiming the installation + +Choose **Install on GitHub** under **Install Cortex Security on GitHub**, pick the repositories GitHub should let it see, and confirm. GitHub sends you back to the **App** tab, which claims the new installation; the server confirms it against GitHub before storing it, so nobody can claim an installation by editing a query parameter. A toast reads **GitHub connected**, or **Could not connect GitHub** when the claim did not work. + +<Note> +Self-hosting a deployment adds one requirement: the App's **Setup URL** has to point at this install page, because GitHub only hands back the installation identifier when it does. The page tells you the exact URL to register: *After install, GitHub must send people to {url}. Register that as the App's Setup URL.* +</Note> + +## What the App asks for + +The page lists what it asks for under **WHAT THE APP ASKS FOR**, with a reason beside each one. The full set the App requests is five permissions, and nothing beyond them. + +| Permission | Access | Why | +| --- | --- | --- | +| Contents | Read | To fetch the pull request's change, and read the manifest that names your tests. | +| Pull requests | Write | To post the review, its inline comments, and the reaction that says the review has started. | +| Issues | Write | To read a comment that mentions the App and reply to it. On GitHub, comment events on a pull request live under Issues. | +| Checks | Write | To report the **Cortex Security** check run. | +| Metadata | Read | Required by GitHub for any app. | + +Commit statuses is requested as read-only and is **not used today**, and would only matter if you wanted the App to read other checks. **Nothing else. In particular not Administration, not Actions, and not Secrets.** + +The App listens for five kinds of event: pull request, issue comment, installation, installation repositories, and pull request review thread. Two of those are worth knowing about, because an installation that does not receive them looks broken rather than unsubscribed: **issue comment** is what makes mentioning the App work at all, and **pull request review thread** is how resolving one of its comment threads counts as a dismissal. + +## The repositories list + +Under **REPOSITORIES** each repository the installation can see has its own switch, labelled `Review pull requests in {name}`. A repository that is off gets no review, no comment and no check run: nothing at all reaches its pull requests. Each row also shows how many pull requests Cortex Security has seen there, or **No pull requests seen yet**, and marks a **Private** repository as such. + +Two more controls sit around the list. + +- **Review new repositories automatically**: *When a repository is added to the installation later, start reviewing its pull requests without asking. Off means it arrives switched off and you enable it here.* This is the setting behind "I added a repository and nothing happened". +- **Add or remove repositories on GitHub** takes you to GitHub, which owns the list of repositories the App can see at all. When there are none, the page says *The installation has no repositories yet. Add some on GitHub and they will appear here.* + +Under **CONNECTION** the state reads **Connected** once an installation is claimed. + +## Where the review policy lives + +The review policy is set once, on the **Policy** tab, and governs **the installation**, which means every repository in it. There is no per-repository policy screen today: if you need different treatment per repository, the levers are the repository switch above and a file in the repository itself. + +A repository can carry its own instructions and rules on the branch under review. Those can make a review stricter or better informed, and they cannot exclude a path, raise a threshold or switch the review off, because the author of a pull request would otherwise have a say over the scrutiny it receives. [Review policy](/security/review-policy) covers both layers and what each may change. + +## Security mode + +Security mode is the switch that enables repository scans. It is separate from the installation, and the two only meet when you start a scan. + +- Turning the mode on does **not** need the GitHub App. Starting a scan does, on a repository this account owns. +- A personal enable is ungated. An **organisation-wide** enable needs an owner or an admin **and** an Enterprise plan, after which members inherit it and need no switch of their own. An admin who enables the organisation keeps their personal switch as well. See [Plans](/getting-started/plans). +- GitHub.com only: **GitHub Enterprise Server is not available yet.** + +[Repository scans](/security/scans) covers what the mode unlocks. + +## States you may see + +| What the page says | What it means | +| --- | --- | +| **Cortex Security is not configured on this deployment** | This deployment has no GitHub App set up, so no pull request is reviewed and there is nothing to install. An operator has to supply the App's credentials first. **Installation details** explains what is missing. | +| *This deployment has no app slug configured, so there is no install link to follow.* | The App exists here but the page has no link to send you to. An operator can find the App's install URL on its settings page. | +| **Connected** | An installation is claimed, and the repositories list is live. | +| *This installation is suspended on GitHub, so no pull request is being reviewed.* | Unsuspend it from the App's settings page on GitHub to resume. | +| **Could not save that** | A change to the list or the auto-enable switch did not stick. Try it again. | + +Cortex Security is not available to guest accounts, and a guest trying to install the App is refused with the reason: a guest session cannot be signed back into later in order to revoke a GitHub installation. + +## Stop reviews + +Four different levels, and people habitually reach for the wrong one. + +| Goal | Do this | +| --- | --- | +| Stop reviewing one repository | Switch **off** `Review pull requests in {name}` on the **App** tab. No comment, no check run, nothing. | +| Keep the reviewer available but silent | **Policy** to **Review pull requests** to **Only when asked**. It then reviews only when somebody mentions the App. | +| Stop reviewing entirely, keep the installation | **Policy** to **Review pull requests** to **Never**. Different from disabling a repository, which also stops the check run being created. | +| Remove Cortex Security from GitHub | Uninstall the App from GitHub. **Add or remove repositories on GitHub** is the link out to its settings. | + +## Related + +- [Security quickstart](/security/quickstart) - install, enable a repository, read a first review. +- [Review policy](/security/review-policy) - everything the policy form governs for this installation. +- [Repository scans](/security/scans) - what Security mode plus an owned repository gives you. +- [Checks and comments](/security/checks) - what lands on a pull request once a repository is on. +- [Security troubleshooting](/security/troubleshooting) - nothing appearing, a suspended installation, a repository that is not being reviewed. diff --git a/security/review-policy.mdx b/security/review-policy.mdx new file mode 100644 index 0000000..f88fbb5 --- /dev/null +++ b/security/review-policy.mdx @@ -0,0 +1,166 @@ +--- +title: "Review policy" +description: "The settings that decide when Cortex Security reviews a pull request, what it reports, how hard a finding lands, and why approval stays with a person" +icon: "scale-balanced" +--- + +The review policy is the one form that decides how Cortex Security behaves on your repositories. It lives on the **Policy** tab inside Security, headed **Review policy**, and describes itself as *what Cortex Security reviews, what it reports, and how hard it lands.* Changes take effect on the next review; choose **Save** and the button reads **Saving…** and then **Saved**. + +This page walks the form in the order it is rendered, gives the default for each control, and then covers the two things the form does not put in a field: what a repository can and cannot set in its own files, and how the reviewer learns from the findings a team keeps dismissing. For what the settings here produce on a pull request, see [Checks and comments](/security/checks); for the stages they are consulted at, see [How a review works](/security/how-a-review-works). + +<Note> +The policy is set once and governs the whole installation, meaning every repository the App is installed on. There is no per-repository policy screen. The only per-repository control is the switch that decides whether a repository is reviewed at all, which lives on the **App** tab; see [Installation and repositories](/security/repositories). +</Note> + +## When to review + +| Control | Values and default | +| --- | --- | +| **Review pull requests** | **Automatically** (the default), **Only when asked**, or **Never**. | +| **Review drafts** | Off by default. | +| **Review again on every push** | On by default. Off means the review is of the pull request as opened. | +| **Skip pull requests larger than** | A number of `files`. Empty reads **No limit**, the default. | +| **Never review pull requests into** | Base branches to leave alone. Empty means all branches are reviewed. | +| **Never review pull requests from** | Authors to leave alone. | +| **Skip pull requests labelled** | Labels that suppress a review. | +| **Review only pull requests mentioning** | Words that must appear before a review happens. | +| **Skip pull requests mentioning** | Words that suppress a review. | + +The two keyword fields share one hint: *One word or phrase per line. Matched anywhere in the title or description.* They are case-insensitive substrings rather than patterns, because somebody typing `WIP` means those characters, and a pattern dialect would turn `[skip ci]` into a character class. The branch, author and label fields are patterns, and the dialect has no character classes either, so a bot account name with square brackets in it is matched literally, bracket for bracket. + +**Only when asked** leaves the reviewer installed and silent: it runs when somebody mentions the App on a pull request, and not otherwise. **Never** switches reviews off while leaving the installation in place, which is different from switching a repository off on the **App** tab, because that also stops the check run being created at all. + +A mention overrides the settings whose job is to keep the reviewer quiet, including a draft and **Only when asked**. It does not override the scope filters in the table above: an excluded branch stays excluded, and the reply names the setting that declined. Mentioning the App with anything other than the word `review` asks it a question instead, which never approves, never requests changes and never creates a check run. + +## What to look at + +| Control | What it does | +| --- | --- | +| **Never review these paths** | Paths to leave out. | +| **Review only these paths** | Paths to restrict the review to. Empty means everything. | +| **Review only these languages** | Languages to restrict the review to. Empty means all. | + +Both path fields share the hint *One pattern per line. Use `**` to cross directories. Leave empty for everything.* Exclusion always wins over inclusion, and an excluded file does not reach a model at all rather than being reviewed and then filtered. + +## What to report + +Two controls are both labelled **Report**, and a finding has to pass both of them. + +The first is the criteria a finding may be filed under: **Security**, **Correctness**, **API contract**, **Tests** and **Performance**. All five are on by default, and an empty set is refused rather than quietly treated as "everything", because the only way to silence Cortex Security should be the setting that says so. + +The second is the families a finding may be reported under: + +| Family | Covers | +| --- | --- | +| **Logic — bugs, security, edge cases** | Bugs, incorrect behaviour, edge cases and security findings. | +| **Usage — contracts and tests** | Usage that is wrong for the language or the interface: a broken contract, a test that does not test. | +| **Style — naming and formatting** | Naming, formatting and structure. | + +All three families are on by default, but naming and formatting opinions are not reported out of the box, because the criteria a finding can be filed under do not cover them. That is deliberate: a reviewer with opinions about naming is the one people switch off, and switching it off takes the injection finding with it. + +Then the two floors, and two numeric fields: + +| Control | Values and default | +| --- | --- | +| **Report findings at least as serious as** | **Blocking**, **Major**, **Minor** or **Note**. Default **Note**, so everything is posted. | +| **Report findings at least as certain as** | **Confirmed in the diff**, **Depends on a caller not shown** or **Worth checking**. Default **Worth checking**, so everything is posted. | +| **Comments per review** | Default **25**, worst first. An owner may set 1 to 100; outside that the save is refused with *Comments per review must be between 1 and 100.* | +| **Instructions for the reviewer** | Free text, up to 4,000 characters per layer: *Review instructions must be 4000 characters or fewer.* | +| **Header on every comment** | Free text, up to 600 characters. | + +The instructions field takes *anything the reviewer should hold in mind: invariants, words that mean something specific here, the mistake the last three incidents had in common.* The header field is not the same thing, and its hint says so: *Prepended above every finding. Not shown to the reviewer and cannot change what it finds.* + +Raising the severity floor cannot silence a security finding from the two layers that run without a model. That exemption, and how the layers differ, is covered in [How a review works](/security/how-a-review-works). + +## General code review + +Cortex Security can also report ordinary code-review findings rather than only security ones. This is a separate layer with its own switch. + +| Control | What it does | +| --- | --- | +| **Enable general code review** | *Off by default per installation. Uses the same verifier and fingerprints as security.* | +| **Post quality findings at or above** | The severity floor for this layer only. | +| **Quality never fails the check** | *Quality uses its own posting threshold. Security findings keep the security gate.* | + +Once it is on, the app labels findings by layer: **Security**, **Quality**, or **Both layers**, and a review's findings line reads posted, discarded and quality counts side by side. + +## How it lands + +| Control | Values and default | +| --- | --- | +| **On a blocking finding** | **Comment only**, **Request changes**, or **Request changes and fail the check** (the default). | +| **Fail the check run at** | A severity. Default **Major**. | +| **Never approve changes riskier than** | See the risk table below. | +| **Edit comments on a new push instead of adding more** | On by default. | +| **Offer a committable fix where there is one** | On by default. | +| **Let Cortex Agent run the change in an isolated runtime** | On by default. | + +The first two work together and are easy to confuse. **On a blocking finding** decides what the review event says and whether the check run may conclude **Failure** at all: with **Comment only** it never does, so a repository that made the check required is not blocked by it. **Fail the check run at** then decides which severity is serious enough, separately from what gets reported, and its hint spells out why they are separate: *Comment on everything and still only block the merge on the serious.* Whether a failing check blocks a merge is GitHub branch protection rather than a Cortex setting. + +The Cortex Agent switch carries its own caveat: *Needs an isolated runtime on this deployment. Without one the run is recorded as unavailable, which is never a pass.* See [Cortex Agent runs](/security/agent). + +### Approval stays with a person + +<Warning> +Cortex Security does not approve a pull request. Where you would expect a setting for approving a clean review, the form shows read-only text instead: **Human approval required**, because *Cortex never approves a pull request automatically. Quality findings remain for a person to review.* There is no toggle behind it and no other way to switch it on. A clean review reports a **Success** check run and leaves the approval to you. +</Warning> + +**Never approve changes riskier than** is still rendered, and it bounds the changes an approval could ever happen on: + +| Value | Meaning | +| --- | --- | +| **Docs, tests and styling** | The narrowest ceiling. | +| **Ordinary application code** | | +| **Dependencies and build configuration** | The default. | +| **Anything (auth, secrets, billing, migrations, infrastructure, CI and public APIs are still never approved)** | The widest ceiling, and still not everything. | + +Authentication, secrets and crypto, billing, migrations, infrastructure, CI and public API surfaces are never approved at any ceiling, matched by path **or** by content, so an authorisation check added to a file with an innocuous name counts. One critical file makes the whole pull request critical. Because approvals are not automatic today, this control does not change the outcome of a review; it is the ceiling that would apply if one were ever posted. + +## The summary comment and diagrams + +**Post a summary comment** is on by default. Its three blocks, **Headline and counts**, **Issues table** and **Confidence score**, can each be **Hidden**, **Shown** or **Folded**. **Post the summary only, with no inline comments** posts the summary and nothing on the lines. **Hide the footer** drops the review number, the commit that was read and the re-trigger line together. **Write the summary into the pull request description** puts the summary in the description instead of a comment. + +Under **Diagrams** you choose which kinds a summary may include: **Sequence diagram**, **Entity relation diagram**, **Class diagram** and **Flow diagram**. At most one appears, chosen deterministically, and a small change gets none. [Checks and comments](/security/checks) describes what all of this looks like on the pull request. + +## What a repository keeps in its own files + +A repository can carry part of its own policy, read from the branch under review. The form says what that can and cannot do: *A repository can keep its own instructions and rules at `.cortex/security.json`, read from the branch under review. It can make a review stricter or better informed. It cannot exclude a path, raise a threshold or switch the review off — those stay here, where the author of a pull request has no say over them.* + +| File | What it is | +| --- | --- | +| `.cortex/security.json` | The repository's policy layer. Up to 64 KB. | +| `cortex-security.json` | The same thing under an alternative name, looked at second. | +| `.cortex/security.md` | Free-text instructions for the reviewer, under the same restrictions. | + +| Accepted | Refused | +| --- | --- | +| Instructions and rules, which are **added** rather than replacing what the form set. Up to 50 rules per layer. | Path includes and excludes. | +| A severity floor, but only **downwards**, towards more findings. | The trigger, draft reviews and the file limit. | +| Criteria, but only as a **union**, never a removal. | The author, branch and label filters. | +| A confidence floor, again only downwards. | How it lands, the comment ceiling and the summary settings. | + +The file nearest a changed file wins, searching up to six directory levels above it, and the repository root is always searched and is always the furthest. A key that is refused is reported back in the review's summary, so a setting quietly dropped and a setting never read do not look identical. + +The layers combine in one direction: the shipped defaults, then the installation's policy from this form, then the repository's own file. A setting the file says nothing about is inherited rather than reset to the default, so a repository whose file is silent about a threshold follows the one you set here when you change it. Scalars replace; rules and instructions accumulate. + +## What a team keeps dismissing + +Put a thumbs-down on one of Cortex Security's review comments, or resolve the thread, and that counts as a dismissal. It is attributed to the **class** of finding, meaning its criterion plus its normalised title without the path, so the same nit on nine files is one preference stated nine times rather than nine patterns that never reach a threshold. + +After three dismissals the reviewer stops posting that class in that repository. All three conditions have to hold: + +1. it was dismissed at least **three** times; +2. it was dismissed more often than it was endorsed, where one thumbs-up undoes three thumbs-down, because somebody taking the trouble to say "keep this" is a stronger signal than three people scrolling past; +3. it was dismissed more often than not, since a class posted thirty times and dismissed three is occasionally irrelevant rather than unwanted. + +Three things are never silenced this way, however often they are dismissed: anything **blocking** or **major**, anything carrying a CWE, and anything filed under **security**. Those dismissals are still counted, so an owner can see that a real finding is being ignored; they simply never stop it being posted. + +A silenced finding is recorded as filtered out rather than rejected, because the second pass never said it was wrong. Reactions are read from the comment list the next time Cortex publishes a review, and only an increase counts, so putting a thumbs-up back after removing it does not train twice. There is no screen listing what a repository has silenced; the effect is visible as findings that stop appearing, and in a review's filtered-out disclosure. + +## Related + +- [Checks and comments](/security/checks) - what these settings produce on the pull request. +- [How a review works](/security/how-a-review-works) - the stages, the second pass, and the verdict arithmetic. +- [Installation and repositories](/security/repositories) - the per-repository switch, the permissions, and how to stop reviews. +- [Cortex Agent runs](/security/agent) - what the isolated-runtime switch does when a deployment has one. +- [Security troubleshooting](/security/troubleshooting) - a green check you expected to be red, or findings that never arrive. diff --git a/security/scans.mdx b/security/scans.mdx new file mode 100644 index 0000000..283611c --- /dev/null +++ b/security/scans.mdx @@ -0,0 +1,114 @@ +--- +title: "Repository scans" +description: "Run an on-demand or weekly scan of a repository you own, read its findings, dismiss one, hand a patch to Cortex Code, or export the scan" +icon: "magnifying-glass" +--- + +A review answers one question: what did this pull request introduce. A scan answers the other one: what is wrong in this tree, on this branch, as it stands today. Cortex Security can scan a repository your account owns, either now or once a week, and it keeps the results inside the app instead of posting them to GitHub. + +This page covers what a scan needs before it will run, how to start one, what each status means, what a finding carries, and the three things you can do with a finding: dismiss it, hand its suggested patch to Cortex Code, or export the whole scan. Scans live on the **Scan** tab, headed **Scans**, which describes itself as *on-demand scans of repositories this account owns. Suggested patches open a Code session. Cortex never applies them.* + +## How a scan differs from a review + +| | Review | Scan | +| --- | --- | --- | +| Question answered | What did this pull request introduce | What is wrong in this tree on this branch | +| Input | One pull request's change, plus the repository indexed at its head | A whole repository at a branch | +| What starts it | A GitHub event, a mention, or **Review again** | **Start scan**, or a weekly schedule | +| Where results appear | On GitHub and in the app | In the app only | +| Second look at each finding | A real verifier; rejections are recorded as discarded | A stub, recorded as such and never as a pass | +| Findings filed under | Review criteria such as security or correctness | A weakness family | +| What you can do with a finding | Reply, add a reaction, resolve the thread | **Dismiss**, open a Code session for the patch, export | + +## What a scan needs + +Three things, and the app tells you which one is missing. + +- **Cortex Security mode** switched on. The hint under the switch is the whole rule: *When this is off, scans do not run. Connect the GitHub App under Install. GitHub.com only.* +- The Cortex Security GitHub App installed on the repository, and the repository enabled. Turning the mode on does not need the App; starting a scan does. +- A repository **this account owns** through that installation. See [Installation and repositories](/security/repositories). + +<Note> +GitHub.com only. The app says it plainly: **GitHub Enterprise Server is not available yet.** Security is also unavailable to guest accounts. +</Note> + +Security mode is a per-account switch. An organisation-wide enable is different: it needs an owner or an admin **and** an Enterprise plan, after which members inherit it without a switch of their own, and the admin who enabled it keeps their personal one. See [Plans](/getting-started/plans). + +## Start a scan + +<Steps> + <Step title="Open the Scan tab"> + From Cortex Code, the home quick action **Run a security audit** opens it, and reads **Security mode is on** once the mode is enabled. The composer's mode menu has a **Security** entry with the hint *Open Security mode for this repository*, which lands in the same place. Inside Cortex Security, it is the **Scan** tab. + </Step> + <Step title="Switch on Cortex Security mode"> + The switch is labelled **Cortex Security mode**. With it off, nothing scans, however the rest of the form is filled in. + </Step> + <Step title="Check the App is connected"> + When the App is installed the card reads **App connected**. When it is not, it reads *Connect the Cortex Security GitHub App to scan a repository this account owns.* with a **Connect GitHub** button. + </Step> + <Step title="Choose the repository and branch"> + **Repository** lists the enabled repositories this account owns. With none, the form says *No enabled repositories. Install the GitHub App and enable a repository you own.* Set **Branch** to the branch you want read. + </Step> + <Step title="Choose when"> + **When** offers **Scan now** or **Weekly scan**. A weekly scan runs *Monday 09:00 UTC on the selected owned repository and branch.* + </Step> + <Step title="Start it"> + Choose **Start scan**. A scheduled scan confirms with `Scheduled as {cron} (UTC).` Before your first scan the list reads **No scans yet**: *Start a scan of a repository this account owns. Findings stay here until you dismiss them or open a Code session for a patch.* + </Step> +</Steps> + +## While it runs + +| Status | What it means | +| --- | --- | +| **Queued** | Accepted and waiting to start. | +| **Scanning** | Reading the tree at the branch you chose. | +| **Validating** | Taking a second look at the findings. | +| **Completed** | Finished. The findings are listed. | +| **Failed** | It did not finish, and carries the line **A failed scan is never an approval.** | + +<Warning> +Every completed scan carries the notice **Validation on this scan is a stub. Findings were not independently verified.** The second look is the same shape as a pull-request review's verifier, but it records a stub rather than a pass, so treat a scan finding as a lead to check rather than as a confirmed defect. A pull-request review does have a real second pass; see [How a review works](/security/how-a-review-works). +</Warning> + +## What a finding carries + +A scan finding gives you a title and details, the path and line it points at, the impact, how to reproduce it, a suggested patch where there is one, a severity, a status, a weakness family, and the repository and branch it came from. Once you have opened a Code session for its patch, the finding remembers that session. + +The families a scan uses are narrower than the review criteria, because a scan is looking for weaknesses rather than judging a change: injection, request forgery, authorization, memory, cryptography, deserialisation and protocol weaknesses. The app may name a family in a shorter form than that. Severities are the same four a review uses, so **Blocking** and **Major** mean the same thing here as they do on a pull request. See [Checks and comments](/security/checks). + +Finding bodies are encrypted at rest. Titles, paths, line numbers, severity, family, repository and branch stay readable, because they are what the list has to show you. A completed scan with nothing in it simply says **No findings.** + +## Act on a finding + +<Steps> + <Step title="Dismiss it"> + Choose **Dismiss** and give a reason under **Why this finding is dismissed**. The field is prefilled with *Dismissed from Security mode*, and a reason is required, so a dismissal is always attributable to something. + </Step> + <Step title="Take the patch into Cortex Code"> + Choose **Open in Code**, or **Approve**. Both do the same thing: they open a Cortex Code session with the suggested patch for you to read. Nothing is written, pushed, or opened as a pull request. The page says so: *Cortex does not apply patches. A Code session is opened for you to review.* Carry on from there in [Sessions](/code/sessions). + </Step> + <Step title="Export the scan"> + **Export CSV** and **Export Markdown** download the scan as `cortex-security-scan.csv` or `cortex-security-scan.md`, which is the way to get findings into a ticket tracker or a spreadsheet. + </Step> +</Steps> + +## Scanning somebody else's repository + +You cannot. The **Repository URL** field takes the address of a GitHub repository, and its only effect is to tell you why that is refused: **This repository is not owned by this GitHub App.** The card explains it as *Cortex Security scans repositories the Cortex Security GitHub App is installed on. A pasted URL that this account does not own is refused.* + +A pasted URL is never a scan target. A scan of a tree the App has no grant to read would look exactly like a working scan of your own repository, which is the reason the field refuses rather than tries. + +## What scans do not do + +- **Nothing is posted to GitHub.** A scan leaves no comment, no check run and no review event. Results live on the **Scan** tab. +- **Nothing is applied.** The patch handoff opens a Code session for a person to read, and that is the only route a scan finding has into your code. +- **Nothing is approved.** A failed scan is never an approval, and a completed one is not a clean bill of health while its validation is a stub. + +## Related + +- [Cortex Security](/security) - the hub, and how scans sit next to reviews. +- [How a review works](/security/how-a-review-works) - the pull-request pass, with a real second look at every finding. +- [Installation and repositories](/security/repositories) - installing the App and enabling a repository you own. +- [Checks and comments](/security/checks) - the severities a finding carries. +- [Security troubleshooting](/security/troubleshooting) - when a scan will not start. diff --git a/security/troubleshooting.mdx b/security/troubleshooting.mdx new file mode 100644 index 0000000..071c1a2 --- /dev/null +++ b/security/troubleshooting.mdx @@ -0,0 +1,153 @@ +--- +title: "Security troubleshooting" +description: "What to check when no check run appears, a review reads Not reviewed, comments are missing, a finding looks wrong, or a scan will not start" +icon: "life-ring" +--- + +Most Cortex Security surprises are a setting doing exactly what it says, somewhere you were not looking. This page is organised by what you actually see: on the pull request, in the review inbox, or on the **Scan** tab. Each entry names the sentence or the state you are looking at, what it means, and the one place to go and change it. + +Two things are worth knowing before you start. The review inbox is where a review explains itself: the row carries a reason line, and opening it shows the findings that were filtered out or rejected. And the review policy is set once for the whole installation, so every "check Policy" below points at the same form. + +## Nothing appeared on the pull request + +<AccordionGroup> + <Accordion title="No check run appears at all"> + Three likely causes, in the order worth checking. The repository is switched off, so nothing runs and no check run is created: look at its switch on the **App** tab. **Review pull requests** is set to **Never** in Policy. Or the pull request was skipped by a filter, in which case its row in the inbox reads **Not reviewed** and carries the reason. + + A skip reason always names the setting that declined, for example that it is a draft and this repository does not review drafts, that the repository reviews only when asked, that the base branch or the author is not reviewed, that a label is missing or suppresses review, or that the change is larger than the file limit. See [Installation and repositories](/security/repositories) and [Review policy](/security/review-policy). + </Accordion> + <Accordion title="The pull request is a draft and nothing happened"> + Drafts are not reviewed by default. Either switch **Review drafts** on in Policy, or ask for one review by mentioning the App in a comment: a mention overrides the settings whose job is to keep the reviewer quiet. + </Accordion> + <Accordion title="Nothing happens when you mention the App"> + Four possibilities. The comment was authored by a bot, which never triggers a review, because that is a loop. The mention sits inside a quote or a fenced code block, which is ignored on purpose, and is what stops GitHub's reply button re-triggering a review on every reply. You edited an existing comment to add the handle instead of posting a new one, and only a newly created comment counts. Or the installation is older than the App's comment event subscription, in which case ordinary reviews keep working and mentions silently do nothing; on a self-hosted deployment, whoever created the App needs to add the issue comment and pull request review thread events. + + A mention does not override scope filters. An excluded branch stays excluded, and the reply tells you which setting declined. + </Accordion> + <Accordion title="A repository you added later is not being reviewed"> + **Review new repositories automatically** is off, so the repository arrived switched off. Turn its switch on under **REPOSITORIES** on the **App** tab, and switch the auto-enable on if you want the next one to arrive enabled. + </Accordion> + <Accordion title="A review looks stuck"> + While a review is in flight the app shows one line of progress, moving through **Queued**, **Reading the change**, **Summarising each file**, **Reviewing file X of Y**, **Verifying findings** and **Posting the review** to **Done**. If it has stopped, the line reads **Could not review** and the row carries the reason. Open the pull request in the app and choose **Review again**, which opens a fresh review of the current head; a toast confirms with **Review queued**, or **Could not queue the review**. + </Accordion> +</AccordionGroup> + +## The check run is not what you expected + +<AccordionGroup> + <Accordion title="The check run says Neutral"> + **Neutral** means exactly what the Checks tab says: *The review could not run, or did not finish. The summary says why. This is never an approval — a change nobody reviewed must not report as one.* In the app, the verdict card reads *No verdict was reached for this commit, so the check is not an approval.* + + The reason is a sentence on the inbox row, and there are seven of them: nothing was available to review with on this deployment, the deployment's model service is not configured, the GitHub App is not configured here, the change could not be read from GitHub, the installation is suspended on GitHub, the review did not finish, or *Every changed file is generated or vendored, so there was nothing to review.* When none of those applies, the fallback is *Cortex Security could not review this change.* + </Accordion> + <Accordion title="The check is green and you expected red"> + Reporting a finding and failing the check are two different settings. **On a blocking finding** may be set to **Comment only**, which never concludes failure, or to **Request changes**, which requests changes and still concludes success. **Fail the check run at** may be set above the severity of what was found. Or the findings were only minor findings and notes, which never fail the check. + </Accordion> + <Accordion title="The check is red but the merge button still works"> + The merge gate is GitHub's, not Cortex's. A failing check only blocks a merge once it is a **required** status check in GitHub branch protection. The **Checks** tab has the workflow for that under **REQUIRING IT**, behind **Copy workflow**. See [Checks and comments](/security/checks). + </Accordion> + <Accordion title="A review found nothing on a change you know is risky"> + Check the row's reason first. If every changed file was generated or vendored, the review is recorded as **failed**, not as passed, and nothing was read. Otherwise a filter is doing it: a path or language filter under **What to look at**, or a severity or confidence floor under **What to report**. Open the review and read the disclosure counting the findings your review policy filtered out, which tells you how many were held back and why. + </Accordion> +</AccordionGroup> + +## Comments and the summary + +<AccordionGroup> + <Accordion title="Inline comments are missing but the summary is there"> + Either **Post the summary only, with no inline comments** is on, or **Comments per review** is set low. Inline comments are posted worst first, and the default ceiling is 25, so a very noisy review can run out of room before it reaches the minor findings. + </Accordion> + <Accordion title="The summary is missing but the comments are there"> + **Post a summary comment** is off, or **Write the summary into the pull request description** is on, in which case the summary is in the description rather than in a comment of its own. + </Accordion> + <Accordion title="A finding's suggested fix is missing"> + A committable suggestion is dropped rather than approximated. A fix that is empty, longer than twelve lines, or that contains a code fence of its own is not rendered, because a **Commit suggestion** button reads as something that was checked and one broken suggestion costs the trust of every correct one after it. + </Accordion> + <Accordion title="A second comment appeared instead of the first one being updated"> + Each comment carries an invisible fingerprint and the next review edits it in place. That is the **Edit comments on a new push instead of adding more** setting, on by default; with it off you get a new comment each time. + </Accordion> +</AccordionGroup> + +## A finding looks wrong + +<AccordionGroup> + <Accordion title="A comment is not useful and you want fewer like it"> + Add a thumbs-down reaction to the comment, or resolve its thread. Both are attributed to the **class** of finding, its category plus its normalised title without the path, so the same nit on nine files is one preference stated nine times. After three dismissals, and only when it has been dismissed more often than it has been endorsed and more often than not, that class stops being posted in that repository. + + Three things can never be silenced however often they are dismissed: anything blocking or major, anything carrying a weakness class, and anything filed under security. Those dismissals are still counted, so an owner can see that a real finding is being ignored. + + Reactions are read from the comment list the next time Cortex publishes a review, and only an increase counts, so removing a thumbs-up and putting it back does not train twice. There is no screen listing what a repository has silenced. + </Accordion> + <Accordion title="A finding points at a line the pull request did not change"> + It should not have been posted, and that is precisely what the second pass rejects. Open the review and read the disclosure counting the findings the verifier rejected: each carries a `Not posted — {reason}.` line, and the two commonest reasons are that the path is not in this pull request, or that it is but the line was not changed here. If one still reached GitHub, add a thumbs-down reaction so the class is counted. + </Accordion> + <Accordion title="A setting in the repository's own config file had no effect"> + A file in the repository can only make a review stricter or better informed. It cannot exclude a path, raise a threshold, or switch the review off, because anyone who can open a pull request can edit it. A key that was refused is reported back in the review's summary, so a setting that was dropped and a setting that was never read do not look the same. See [Review policy](/security/review-policy). + </Accordion> +</AccordionGroup> + +## Cortex Agent + +<AccordionGroup> + <Accordion title="The run says Nothing was run"> + The run page always names the reason: nothing was available to write a program with, this deployment has no isolated runtime for Cortex Agent to use, there was nothing in the change a program could demonstrate, or the runtime could not be reached. The second is the common one, because an isolated runtime is off by default on a deployment. + + In every case the page adds *A run that could not happen is never a pass, and nothing here counts towards the review's verdict.* See [Cortex Agent runs](/security/agent). + </Accordion> + <Accordion title="An artifact will not open"> + A file that cannot be read shows *This file could not be read.* A long one shows only its beginning, and says so. A run that kept nothing says the programs it wrote printed their results rather than writing them out, and the step list is then the evidence. + </Accordion> +</AccordionGroup> + +## Scans + +<AccordionGroup> + <Accordion title="Scans do not run"> + **Cortex Security mode** is off, the GitHub App is not installed, or the installation is suspended on GitHub. The **Scan** tab shows which: the mode switch, and a card reading either **App connected** or *Connect the Cortex Security GitHub App to scan a repository this account owns.* + </Accordion> + <Accordion title="A pasted repository URL is refused"> + By design. The refusal card reads **This repository is not owned by this GitHub App.** Scans only cover repositories the App is installed on and this account owns, and a pasted URL is never a scan target. See [Repository scans](/security/scans). + </Accordion> + <Accordion title="A completed scan says its validation is a stub"> + That is accurate, not a fault: *Validation on this scan is a stub. Findings were not independently verified.* A scan finding is a lead to check. A pull-request review is the surface with a real second pass over every finding. + </Accordion> + <Accordion title="Security mode will not turn on for the organisation"> + An organisation-wide enable needs an owner or an admin and an Enterprise plan. A personal enable needs neither, so turn it on for yourself and ask an owner about the organisation. See [Plans](/getting-started/plans). + </Accordion> +</AccordionGroup> + +## Installation and access + +<AccordionGroup> + <Accordion title="The whole Security area says it is not configured"> + **Cortex Security is not configured on this deployment** means the deployment has no GitHub App set up. Nothing a user can change fixes it; an operator supplies the App's credentials, and **Installation details** says what is missing. + </Accordion> + <Accordion title="Nothing is being reviewed and the App tab mentions a suspension"> + *This installation is suspended on GitHub, so no pull request is being reviewed.* Unsuspend it from the App's settings page on GitHub, and reviews resume. + </Accordion> + <Accordion title="Security refuses you outright"> + Cortex Security is not available to guest accounts, and a guest trying to install the App is refused with the reason. Sign in with a full account. GitHub Enterprise Server is also not available yet, so a repository that is not on GitHub.com cannot be reviewed or scanned. + </Accordion> +</AccordionGroup> + +## About error codes + +<Note> +The seven sentences a failed review can carry are not platform error codes. They are stored with the review and rendered as prose, so there is no error-code page to look one up in: the sentence on the row is the whole explanation. +</Note> + +Three platform codes can legitimately show up around Security, and those do have pages: + +- [entitlement_required](/problems/entitlement_required) - a guest account, or an organisation-wide mode enable without the plan for it. +- [validation_failed](/problems/validation_failed) - a policy saved outside its numeric limits, or a scan asked for by URL. +- [service_unavailable](/problems/service_unavailable) - the deployment has no GitHub App configured. + +If a problem survives all of the above, check [status.cortex.foundation](https://status.cortex.foundation) and then [report a bug](/getting-started/report-a-bug) with the pull request and the commit the review names. + +## Related + +- [How a review works](/security/how-a-review-works) - the stages, the second pass, and how the verdict is decided. +- [Review policy](/security/review-policy) - every setting named on this page. +- [Installation and repositories](/security/repositories) - the repository switches and the states the App tab shows. +- [Checks and comments](/security/checks) - the check run, and making it required. +- [Repository scans](/security/scans) - what a scan needs before it will start. diff --git a/status.mdx b/status.mdx deleted file mode 100644 index b38cc13..0000000 --- a/status.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: "System status" -description: "Live availability for Cortex Web, API, Chat, Code, and Bot — incidents, maintenance, and history." -keywords: ["uptime", "outage", "incident", "maintenance", "availability"] ---- - -<div className="status-cortex-logo"> - <img src="/logo/banner-light.png" alt="Cortex" width="220" /> -</div> - -Cortex publishes live component health, incident history, and scheduled maintenance on the public status page. - -<p className="ink-cta-row"> - <a className="ink-btn" href="https://status.cortex.foundation">Open status.cortex.foundation</a> - <a className="ink-btn ink-btn-quiet" href="/getting-started/troubleshooting">Troubleshooting</a> -</p> - -<Note> -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. -</Note> - -## What we report - -| Component | What it covers | -| --- | --- | -| **Web** | The Cortex website and signed-in app shell at [cortex.foundation](https://cortex.foundation) | -| **API** | Product API routes used by Chat, Code, Bot, Design, and the CLI | -| **Chat** | Conversations, tools, Deep Research, images, and related Chat services | -| **Code** | Code Cloud sessions, desktop/CLI coding agent backends, and related Code services | -| **Bot** | Bot computers, approvals, routines, and related Bot services | - -Component names stay product-facing. Individual incidents may mark one or more of these surfaces as affected. - -## 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. -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. - -## Documentation vs status - -| Resource | Use it for | -| --- | --- | -| [status.cortex.foundation](https://status.cortex.foundation) | Live uptime, incidents, maintenance windows | -| [Troubleshooting](/getting-started/troubleshooting) | What a specific product message means and what to do next | -| [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. -- [Chat](/chat) · [Code](/code) · [Bot](/bot) · [CLI](/cli) — the surfaces status reports on. -- [Problem catalog](/problems) — the error codes behind a failed request.