CLI reference
The kya-os commands and flags for setting up Checkpoint, how --project resolves, and the environment variables and files the CLI reads and writes.
kya-os --help and kya-os <command> --help list everything the installed version supports.
setup
A live sign-in on the same Checkpoint is reused, so a second run doesn't open the browser. If the project you name isn't part of that sign-in, setup signs in again with it preselected so you can grant it. A name no project has yet is offered on the consent page instead, to create and grant in one step. With nothing named, the offer is this repository's name, and a granted project by that name is linked without asking.
detect install
Without a sign-in, detect install uses the project you name as given, since the pixel and beacon need only the project ID; it says so. What it writes:
On .NET, the page <head> is in a different file for each project type:
- Blazor Web App:
Components/App.razor - Blazor WebAssembly:
wwwroot/index.html - Blazor Server upgraded from .NET 7 or earlier:
Pages/_Host.cshtml(Pages/_Layout.cshtmlif it started on .NET 6) - MVC:
Views/Shared/_Layout.cshtml - Razor Pages:
Pages/Shared/_Layout.cshtml - Web Forms (.NET Framework):
Site.Master
With --surface sdk and no runtime key where the app reads it, a signed-in detect install offers to mint the app's key. It asks first; --yes skips the prompt, and a dry run only says it would. The key is named kya-os CLI · sdk · <host> - <repository>, is returned once, and has read permission. The plan's API key limit applies, as it does to dashboard keys.
- Next.js and Express: the CLI adds the env file to
.gitignore, then writes the key to.env.local(Next.js) or.env(Express). - ASP.NET Core: the CLI runs
dotnet user-secrets initfirst, then stores the key and the project ID asCheckpoint:ApiKeyandCheckpoint:ProjectIdin the project's user secrets, outside the repository. The key reachesdotneton stdin, never its command line. In production, setCheckpoint__ApiKeyandCheckpoint__ProjectIdin the host's environment. - Java: the CLI prints where the key goes.
Signed out, detect install says to sign in with kya-os login and re-run it, which mints the key.
Existing files only ever gain one block, marked Checkpoint Detect. A file that already has it is left alone, so a second run changes nothing. An existing middleware.ts or proxy.ts is never overwritten; the lines to compose into it are printed instead. A failed package install stops the run before anything that imports the package is written.
Browser posture
--surface beacon installs a beacon the CLI has checked, and every project already has the posture key behind the signed token your server verifies. Set up browser posture walks through the whole path.
Before it installs, the CLI resolves the latest @kya-os/checkpoint-beacon on npm, verifies the tarball against the sha512 integrity the registry lists, and hashes beacon.min.js with sha384 for the script tag. It then fetches the same file from jsDelivr and installs nothing unless the bytes match. A script tag gets a versioned URL with integrity and crossorigin="anonymous".
The beacon version decides how much posture wiring you get:
A run at 1.4.3 or later upgrades an earlier install in place.
The CLI decides file ownership by comparing a file's whole text with what it generates, not by a marker:
- A generated
Checkpoint Detectblock orcheckpoint-detect.tsxis replaced or updated on the next run. - Files under
_checkpoint/<version>/are rewritten when they differ. - Anything you edited, and any beacon install the CLI didn't write, is left alone with the reason.
- A run stops at its first failed step, so a page never references a file that wasn't written.
Configuring posture
Every project has a posture key, so there is nothing to turn on. On every surface the CLI calls Checkpoint's management posture API: it reads the project's posture (the first read creates the key, and an existing key is never rotated) and, with --origins, replaces the additional origins. All of it needs a sign-in, and setup signs you in as part of the command.
The posture calls run even when the install plan isn't applied, because there's no terminal and no --yes, or you answered No. --origins still changes Checkpoint.
The CLI checks the key and prints the configuration:
Origins the Java and .NET verifiers would reject are left out of the config blocks, with the note These origins are left out of the verifier config because Java and .NET would reject them: .... They are empty labels, odd characters, labels over 63 characters or edged by -, and single-label extras. A single-label primary domain such as https://localhost:3000 is accepted. Additional origins need two labels, and --origins refuses single-label hosts.
Proxy targets
--proxy <path> takes letters, digits, _, -, and /, up to 64 characters including a leading /, with no trailing /, no //, and no empty segment. The beacon's endpoint becomes <path>/api/v1/beacon, prefixed by a Next.js basePath when the CLI can read one.
When you're signed in, the CLI mints a project API key with the proxy purpose and the forward permission only, and stores it as CHECKPOINT_PROXY_KEY. Minting needs a project owner or admin, and the key counts against the plan's API key limit. The key is shown once and never printed. Signed out, the CLI asks you to sign in and re-run, or to set the variable yourself. Forward edge evidence covers what the key can do.
The nginx block and the Akamai rule clear Cookie, Authorization, and the JA4, challenge, and challenge-id headers by name. Delete any other KYA-Forwarded-* header yourself. For nginx, Cloudflare, and Akamai, nothing is applied.
The generated Next.js proxy behaves like this:
The Content-Security-Policy directives the CLI prints depend on whether the proxy landed and how the script is delivered:
- It always lists
base-uri 'none'(add it with a nonce-based policy) andtrusted-types checkpoint-beacon(add it when the page enforces Trusted Types). Add them only if they apply. - A project with no static directory still loads the script from jsDelivr, so
script-srckeeps the CDN, and the CLI says so. - The CLI reports the collapsed policy only when every step landed. A skipped or failed step counts as not in place.
- With
--proxyand a static directory, an HTML page's script tag also points at a self-hostedbeacon.min.js, written to the same_checkpoint/<version>/directory.
posture in --json
Both setup and detect install add a posture object to their report. Outer keys with no value are left out. Inside state, primaryOrigin is null when the project has no domain.
The proxy key's value is never in the report. A minted key appears in keys by keyId, name, and preview, and the plan lists a writeSecret action for where it was stored.
detect doctor
kya-os detect doctor --url <page> fetches a page and checks that the beacon and its posture path can work there. It reads the HTML, then probes the files and headers the beacon needs. When the page has no beacon.min.js tag, it also reads up to 20 same-origin scripts to find a beacon inside a bundle.
It exits 1 when any check is fail, and 0 for warn and info.
login, logout, whoami, projects
The sign-in is a management session for a person. It lists your projects and links repositories to them, and Checkpoint's runtime API refuses it, so it can never stand in for an app's API key. Access tokens last 15 minutes and renew silently; the session ends after 30 days without use, and after 90 days regardless. On Linux the session needs a Secret Service keyring (GNOME Keyring or KWallet); see Troubleshooting for machines without one.
mcp create
kya-os mcp create <name> runs @kya-os/create-mcpi-app for Cloudflare Workers, the runtime that pulls per-tool protection from Checkpoint. It's pre-filled with the linked project and your repository's package manager, and runs with no prompts. When you're signed in, it then mints the server's key (read and write, for proofs and tool discovery) into the new server's gitignored .dev.vars. The key never goes on the scaffolder's command line.
Without a terminal, pass --yes or --no-key: the key is decided before anything is scaffolded, so a server is never left half set up. The scaffolder needs Node.js 22.12 or newer.
Then run it locally with npm run dev (the CLI prints your package manager's form). Before the first npm run deploy, sign wrangler in once with npx wrangler login, then upload the server's secrets, the key among them, with npx wrangler secret bulk .dev.vars.
govern
kya-os govern install --agent claude adds a Claude Code PostToolUse hook to this repository. After every tool call, Claude Code runs kya-os hook post in the background, and the call appears in the project's Activity feed as an observed verdict. Nothing is blocked.
- Sent: the tool's name, the session, and the call's ID. The tool's input and output are never sent, since they can hold file contents and secrets.
- Never in the way: the hook runs asynchronously, gives up after three seconds, and exits 0 on any failure.
- Key: the project's read-only runtime key, read from the repository's gitignored
.env.localor.env. If the key is only in your shell'sCHECKPOINT_API_KEY,installsaves it to.env.local, because the hook runs inside Claude Code, which may not see your shell. When there's no key and you're signed in,installmints one. - Origin: the hook reports only to the Checkpoint it was installed for (
hook post --origin …), so a later edit to the committed link can't redirect the key.
Your other hooks and settings are kept, and a second install changes nothing, unless the hook points at another Checkpoint or another kya-os binary: then it's replaced, and the state is updated. kya-os govern uninstall --scope <scope> removes only the kya-os hook.
How --project resolves
Every command that needs a project takes the first of:
- the
--projectflag; - the
KYA_OS_PROJECTenvironment variable; - the nearest
.kya-os/project.json, from the current directory up to the repository root; - the only project the sign-in covers.
A value matches a project by ID, or by exact name, ignoring case. A name shared by several projects is refused with the list of matches, and with several projects and nothing selected, setup asks, offering a new project too (or, without a terminal, lists them and stops). Only a project ID preselects a project on the consent page; any other value is matched there by name, or offered as the name of a new project.
Environment variables
The installer's own variables are on Installation.
Files
{
"schema": "kya-os.project-link.v1",
"origin": "https://kya.vouched.id",
"organizationId": "5b1f3a9e-…",
"projectId": "9c2d7e41-…",
"name": "acme-web"
}A link that names another Checkpoint origin (staging, a local server) is ignored, with a message, rather than resolved against the wrong one.
JSON output
With --json, a command prints one JSON document on stdout, and progress, prompts, and package-manager output go to stderr. setup reports the link and what Detect did:
{
"origin": "https://kya.vouched.id",
"signedInNow": true,
"organizationId": "5b1f3a9e-…",
"project": { "id": "9c2d7e41-…", "name": "acme-web" },
"link": { "path": "/home/me/acme-web/.kya-os/project.json", "state": "written" },
"detect": {
"status": "applied",
"report": {
"surface": "pixel",
"outcomes": [{ "outcome": "applied", "description": "edit app/layout.tsx (before </body>)" }],
"notes": ["…"]
}
}
}