CLI reference

The kya-os commands and flags for setting up Vouched KYA, how --project resolves, and the environment variables and files the CLI reads and writes.

From kya-os 2.5.1, JavaScript builds use a caret dependency on @kya-os/checkpoint-beacon, and their build, dev, and typecheck commands synchronize companion assets from the installed version. The Java dependency floor is 0.2.2. The beacon's reload persistence needs @kya-os/checkpoint-beacon 1.4.4 or later.

CommandWhat it does
kya-os setupSign in, choose the project, link the repository, and install Detect for the app in this directory
kya-os loginSign in as yourself, in this machine's browser or with --device for a code
kya-os logoutRevoke this machine's sign-in on Vouched KYA, then delete it locally
kya-os whoamiWho is signed in, the organization, and the projects the sign-in covers (* marks this repository's)
kya-os projects listThe projects the sign-in covers
kya-os projects use <id or name>Link this repository to a project
kya-os detect installAdd Detect (pixel, beacon, or server SDK) to the app in this directory
kya-os detect doctorCheck a live page: its Content-Security-Policy, the beacon files it loads, and whether its origin can carry browser posture
kya-os mcp create <name>Scaffold a KYA-OS MCP server for Cloudflare Workers, tied to the linked project, with its own key
kya-os govern install|uninstallReport a coding agent's tool calls in this repository to the project's Activity feed
kya-os checkpoint key set|show|clearStore, check, or remove the project's runtime key (CHECKPOINT_API_KEY) in .env.local
kya-os checkpoint credentials …The management sign-in (status, login, logout, session) and, for owners and admins, runner workload keys, task grants, the organization's own model provider keys (model-keys), legacy delegations and reviewed identity changes
kya-os doctorCheck system health and compatibility

kya-os --help and kya-os <command> --help list everything the installed version supports.

setup

FlagEffect
--project <id or name>The project to link. See How --project resolves.
--surface <surface>pixel (default: no key, no dependency), beacon, or sdk (server middleware; mints the app's key if it has none)
--deviceApprove the sign-in from another device with a short code, instead of this machine's browser
--skip-installSign in and link the project; install nothing. Posture still runs
--dry-runPrint what would change and change nothing
-y, --yesApply without asking. Without a terminal, nothing is applied unless this is given. --non-interactive is an alias.
--origin <url>The Vouched KYA origin to sign in to. Defaults to CHECKPOINT_API_URL, then https://kya.vouched.id. This is not a page origin; see --origins.
--origins <list>Comma-separated page origins allowed to carry posture besides the project's domain. The list replaces the project's, so an origin you leave out is removed, and the CLI reports what it added and removed. A bare host such as shop.example.com becomes https://shop.example.com, and a path or query is dropped. Wildcards, the apex rule, and the limit of 20 are under Verifying the posture token.
--proxy <path>Beacon only. Serve the beacon and its ingest through your own domain under this path, for example /_cp, so assets and ingest can stay on your origin. Mints a forward-only key and writes the proxy for Next.js, or prints the nginx, Cloudflare, and Akamai config.
--jsonPrint one JSON document on stdout; progress goes to stderr

A live sign-in on the same Vouched KYA origin 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

FlagEffect
--surface <surface>pixel (default), beacon, or sdk
--project <id or name>The project, when this repository isn't linked yet
--dry-runPrint the plan and change nothing
-y, --yesApply without asking
--origins <list>, --proxy <path>As for setup. detect install has no --origin.
--jsonPrint one JSON document on stdout

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:

Stackpixelbeaconsdk
Next.js, App Router<Script> before </body> in the root layout, plus its importthe package, a 'use client' component, mounted in the layoutthe package, then proxy.ts (Next.js 16+) or middleware.ts at the root or in src/
Next.js, Pages Routera script tag before </Head> in _documentthe package, plus the line to add to your client entryas App Router
Vite SPA, SvelteKitthe pixel loader in the HTML entrythe full package and client initializationnone; use the pixel or the Gateway
Static site without a JavaScript buildthe pixel loader in the HTML entrythe pinned CDN script tagnone; use the pixel or the Gateway
Express 4printed, for the HTML you renderthe package, plus the line to addthe package, plus the mount lines to add
Express 5printedthe package, plus the line to addrefused: the SDK's peer dependency is Express 4
ASP.NET Core (net8.0+)printed, for the page <head> (see below)printeddotnet add <project> package KyaOs.Checkpoint, plus the Program.cs lines to add
.NET Framework 4.6.2 to 4.8.1printed, for the page <head> (see below)printedthe Web.config settings and module to add
Java 21+ (Maven, Gradle)printed, for your page templateprintedthe dependency to add; below Java 21 it's refused

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.cshtml if 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 init first, then stores the key and the project ID as Checkpoint:ApiKey and Checkpoint:ProjectId in the project's user secrets, outside the repository. The key reaches dotnet on stdin, never its command line. In production, set Checkpoint__ApiKey and Checkpoint__ProjectId in 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.

The CLI adds or updates its generated Checkpoint Detect wiring. It leaves edited or unrecognized files alone and prints the changes to compose manually. 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 the full @kya-os/checkpoint-beacon package for JavaScript builds. Every project has a posture key for the signed token your server verifies. Set up browser posture walks through browser and server configuration.

StackBeaconPosture wiring
Next.js App Router with a root layoutThe full package and a generated checkpoint-detect.tsx client component, mounted in the root layoutThe component exports checkpointPostureHeaders(), which reads the active beacon's getPostureHeaders()
Vite with an HTML entryThe full package and checkpoint-detect.js, loaded by a module tag added to the HTMLThe generated module exports the per-request header getter
Next.js Pages Router, SvelteKit, Remix, and other Node appsThe full package and a root checkpoint-detect.js module; the CLI prints the import to add to the client entryThe generated module exports the per-request header getter; application wiring is manual
Static HTML without a JavaScript buildA pinned script tag with integrity and an initialization blockA same-origin worker when a static directory exists; window.checkpointPostureHeaders()
Java, .NET, and other server templates without a JavaScript buildA pinned script snippet to add to the page templateThe worker and posture helper are handled as for static HTML

For package installs, the CLI resolves the full beacon package and adds a caret range, then uses the version actually installed to supply its worker and lazy signals files. The generated root checkpoint-beacon-assets.cjs script copies both companion files and writes checkpoint-beacon-assets.json beside the generated client module. Whichever of the application's build, dev, and typecheck scripts exist now call it with --run, which synchronizes the assets and then runs the original command. The CLI saves each original command as checkpoint:build, checkpoint:dev, or checkpoint:typecheck. Beacon initialization imports those URLs. A repeated install does not wrap the scripts twice, and it does not depend on a postinstall hook. Running the helper again reads the installed package, so a lockfile update cannot leave the old worker paired with new beacon code.

For script tags, the CLI resolves the published beacon, verifies the npm tarball against its registry integrity, computes the script's SHA-384 hash, and checks the matching jsDelivr bytes. The tag is pinned to that version with integrity and crossorigin="anonymous". These installs retain the pinned script path.

Use the shell's beacon instance in the shared API transport. The following browser-only example reads posture at the moment the request starts:

import { CheckpointBeacon } from '@kya-os/checkpoint-beacon';

const beacon = new CheckpointBeacon({ projectId: '<project UUID>' });

export function generate(body: string) {
  return fetch('https://api.example.com/generate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...beacon.getPostureHeaders(),
    },
    body,
  });
}

getPostureHeaders() is synchronous and adds no Vouched KYA network call to the request. It returns the active session header and, when available, an unexpired token for that project and session. It returns no posture headers after the session's idle deadline. The getter never waits for collection, renewal, or a token. A new visit has no signed token until the first ingest response, so a request sent with the getter alone carries only the session header; an HTTPS reload can restore an unexpired token for the same project and session. To give a page's first call a chance at a token, await prepareForAction({ action }) before it, or send it through the hosted script's checkpointFetch, which waits once, up to 3 seconds. Missing posture remains unknown and grants no permission.

Use this read only for your own API. Read it again on every request and replace any earlier posture headers; never save them as client-wide defaults. One application shell owns initialization, and micro-frontends use its current instance or exported header getter. The CLI does not rewrite existing application API calls.

A caret range permits compatible package updates when dependencies are resolved. A frozen lockfile and a deployed bundle stay on their existing version until you update, rebuild, and deploy. Keep the generated asset synchronization step in both build and dev commands.

Generated itemRule
checkpointPostureHeaders()Reads the current beacon's getPostureHeaders(); it returns an empty object before initialization
workerUrl, lazySignalsUrlPoint to files copied from the installed beacon version into the application's static directory
basePath (Next.js)A readable string literal prefixes browser asset URLs and the endpoint; compose a dynamic prefix yourself

A real install refuses a beacon older than 1.4.3 because it lacks posture forwarding. A dry run reports the gap without changing the application. The newer persistence behavior needs @kya-os/checkpoint-beacon 1.4.4 or later, even when an older release already supports getPostureHeaders().

The CLI leaves edited initialization and proxy files for manual composition. Check that the generated synchronization command still runs before your build and that both asset URLs reach files from the installed version.

Configuring posture

Every project has a posture key, so there is nothing to turn on. On every surface the CLI calls Vouched KYA'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 Vouched KYA.

SituationResult
A terminal, no --yes, no --originsAsks Other page origins allowed to carry posture, prefilled with the current list. A terminal means both stdin and stderr are terminals
No terminal, or --yesAsks nothing; changes the origins only with --origins
Signed out, detect installFinishes the install, notes that browser posture was not configured, then exits non-zero and asks you to run kya-os login and re-run. A signed-out --dry-run still exits zero
--dry-runDoesn't ask Vouched KYA for posture, because the first read creates the key. Reports that it would read and confirm the key, and previews what --origins would replace
No project domain and no --originsSays no token can be issued, then exits non-zero: set the project's domain, or pass --origins
Only wildcard originsSays the verifier needs one exact page origin, then exits non-zero: set the project's domain, or add an exact origin with --origins
No domain but an additional originUses the first additional origin as the page origin in the snippets and says so
A domain the Java and .NET verifiers can't useThe note names the domain and uses the first additional origin instead
The pixel or sdk surface, or no surfacePosture is still configured, and the CLI says browser posture needs the beacon on your pages: run kya-os detect install --surface beacon. With --surface sdk and no verifier config for your stack, it exits non-zero
--surface beacon and the latest published beacon is older than 1.4.3Stops before changing your pages or dependencies and exits non-zero: that beacon has no posture helper to carry the token. --dry-run still plans it and says why
An origin that isn't validRefused before anything is installed. The error reads Error: --origins, then Caused by: origin 1: Only https:// origins are supported, with the origin's position. The terminal prompt shows the reason and asks again
--origins ""Refused before anything is installed: --origins needs at least one origin; leave the flag out to keep the current list
A blank answer at the origins promptRemoves all additional origins (the prompt says "blank for none")

The CLI checks the key and prints the configuration:

OutputWhat it is
Key checkFetches the keys URL the project reports, retrying up to three times, two seconds apart, on 404, and compares the key id and public key with the project's. It fetches only a URL on the sign-in origin or https://kya.vouched.id, at the path /api/v1/beacon/keys with projectId=<this project> as the sole query parameter. For any other URL it fetches nothing, reports key: not confirmed, and drops the Java block.
Result linekey: confirmed at the keys endpoint or key: not confirmed, with a missing: line that says why; an unconfirmed key exits non-zero
Server configurationBlocks for the stacks it detects (Next.js, Express, ASP.NET Core, Java). The Next.js, Express, and ASP.NET Core blocks carry the key id and public JWK. The Java block uses the confirmed public key when available; use the pinned-key configuration in Set up browser posture when verification must not fetch keys during an API request. No block prints without a usable page origin.
CORS lineAccess-Control-Allow-Headers: KYA-Posture, KYA-Posture-Session, for cross-origin APIs
CSP directivesThe Content-Security-Policy directives the page needs. They print on every run, and --dry-run previews them.

Java dependency instructions select the latest stable Maven release at or above 0.2.2, with 0.2.2 as the fallback. Dependency and verifier snippets are printed for you to apply; the CLI does not edit Maven or Gradle files or install the Java configuration. Confirm that version is published before using it. A pinned public key verifies posture locally. BrowserPostureOptions.remoteKeys(...) fetches the keys in the background, so no request waits for a fetch. checkpoint.warmup(), which the servlet and JDK HTTP server filters call at startup, runs the first fetch before traffic. A request finds no key, and fails posture verification, before the first fetch succeeds and after a refresh fails. Pin the public key if posture verification must not depend on the keys endpoint being reachable. After rotating the project key, update the server's key ID and coordinates before activating the new signer.

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.

TargetWhat the CLI does
Next.jsWrites a helper, checkpoint-beacon-proxy.ts, and one entry file whose matcher lists only <path>/api/v1/beacon: proxy.ts on Next.js 16 and later, middleware.ts before that, under src/ when the app uses src/app or src/pages. An existing entry file the CLI didn't write is never overwritten; the lines to add are printed.
nginxPrints a location block that proxies to https://kya.vouched.id/api/v1/beacon, starts with include /etc/nginx/checkpoint-proxy-key.conf; (a file you create with the key), and sets X-API-Key and KYA-Forwarded-IP from $remote_addr.
CloudflarePrints a Worker to route at your domain and path, and the wrangler secret put CHECKPOINT_PROXY_KEY command. The Worker reads cf-connecting-ip, answers 502 without the key or the IP, forwards kya-forwarded-ja4 from Cloudflare bot management when present, and removes X-API-Key, Cookie, Authorization, and every KYA-Forwarded-* header the visitor sent.
AkamaiPrints a property rule for your default rule that sets X-API-Key from the sensitive user variable PMUSER_CHECKPOINT_PROXY_KEY and KYA-Forwarded-IP from AK_CLIENT_IP. Vouched KYA hasn't verified the rule against a live property.

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:

BehaviorDetail
Missing dataAnswers 502 when it has no key or can't read the visitor's IP, which it takes from x-real-ip, else the first x-forwarded-for hop.
HeadersRemoves x-api-key, cookie, authorization, and kya-forwarded-* from the request before setting its own.
KeySet CHECKPOINT_PROXY_KEY in your host's environment as well, since .env.local isn't deployed. A CHECKPOINT_PROXY_KEY you've already stored is kept, and no key is minted.
PathThe helper accepts a trailing slash and passes the query string to Vouched KYA.
Re-runsThe CLI recognizes your helper when its BEACON_PATH matches, even after a formatter requotes it. A helper you edited for a different path stops the run with an error that says to set BEACON_PATH to the new endpoint or delete the file.

The Content-Security-Policy directives the CLI prints depend on whether the proxy landed and how the script is delivered:

DirectiveValue
connect-src'self' https://kya.vouched.id, or 'self' when the proxy is in place
script-src'self' when the script is self-hosted: a Next.js App Router install, a package install, an HTML page with --proxy and a static directory, or a non-Node stack with --proxy and a static directory (wwwroot, src/main/resources/static). https://cdn.jsdelivr.net for a CDN script tag.
worker-src'self'
  • A nonce-based policy still needs the response nonce and 'strict-dynamic'; 'self' alone does not authorize a script under that policy.
  • It always lists base-uri 'none' (add it with a nonce-based policy) and trusted-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-src keeps 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 --proxy and a static directory, an HTML page's script tag also points at a self-hosted beacon.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.

FieldValues
statusconfigured, dryRun, unavailable (this Vouched KYA doesn't serve browser posture, or reading it failed; nothing changed)
statekeyId, publicJwk, primaryOrigin, origins, keysUrl
keyConfirmedWhether the keys endpoint confirmed the project's key. It is present whenever the check ran, so not on a dry run or when posture was unavailable.
config{ title, snippet } server configuration blocks
cors, cspThe Access-Control-Allow-Headers line, and the directives for the Content-Security-Policy
originsChange{ added, removed } after --origins
incompleteEach gap that makes the command exit non-zero: posture unavailable, no usable page origin, key not confirmed, origins not changed, no verifier config
notesNon-fatal notes

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 its beacon configuration, files, and headers. 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.

FlagEffect
--url <page>The http or https page to check. Required. A malformed value stops with the --url is not a valid http(s) URL, without echoing the input.
--project <id or name>The project for the posture checks. Defaults to KYA_OS_PROJECT, then the repository's link.
--jsonPrint { url, checks: [{ name, status, detail, fix? }] } on stdout. status is ok, info, warn, or fail.

It exits 1 when any check is fail, and 0 for warn and info.

LimitValue
RequestTimes out after 10 seconds, reads at most 5 MiB, and follows up to 10 redirects
A file on another originIsn't fetched when it points to a private or local address, and that shows as a warn
A file on the page's own originIs fetched
The --url pageCan be at a private or local address, so you can check a local server. A redirect from a public page to another origin that is or resolves to a private or local address is refused, and so is a redirect from a same-origin file
CheckWhat it reports
page, page size, page nesting, page complexityfail when the page can't be fetched or doesn't answer 200. A page over the scan limits is warn, and only the start of it is read. A page too deeply nested or too complex to scan stops the scan with a warn, and beacon then reports warn, not fail.
beaconfail when no beacon script tag or configuration is found, with the fix kya-os detect install --surface beacon. warn when the scan was cut short and it wasn't found in the part read. info when it's found inside a bundled script. warn also when a script it needed to read couldn't be read, or when the page has more than 20 same-origin scripts.
beacon configinfo when the scan was cut short and no endpoint was found, so the default https://kya.vouched.id/api/v1/beacon is assumed.
beacon script, lazy signals chunk, workerok on a 200 served as JavaScript. fail or warn on another status, an unreachable file, or a type a browser refuses. A worker on another origin fails, because it must be served from the page's origin. A worker the doctor derived rather than read from the page is warn; a derived lazy chunk that fails is fail. No worker check runs when the beacon config sets useWorker: false. Only false, !1, true, and !0 count, the last duplicate wins, and keys inside workerOptions are ignored.
beacon script integrityok when the served bytes match the tag's integrity hash (sha256, sha384, or sha512, the strongest listed). fail when they differ, because browsers refuse to run the script. info when the tag has no usable hash
beacon script corsfail when a cross-origin beacon script tag has integrity but no crossorigin, or the host's response headers don't fit the tag: anonymous needs Access-Control-Allow-Origin of * or the page's origin, and use-credentials also needs Access-Control-Allow-Credentials: true
content-security-policy, csp report-onlyok when the page sets none. A report-only policy is info and isn't checked. Header and <meta> policies, several policies, nonces, hashes, and 'strict-dynamic' are read. A tag whose integrity lists several hashes passes a hash-based policy only when the policy lists every one.
csp script-src: init script, csp script-src: beacon script, csp script-src: lazy signals chunk, csp worker-src: worker, csp connect-src: ingestfail when the policy blocks that file or the beacon's endpoint (ingest is checked for a proxy path too); a blocked worker the doctor derived rather than read from the page is warn. The fix names the source to add
csp base-uriok for 'none' or 'self'; warn under a nonce or hash policy with none. The beacon still works
csp trusted-typesfail when the page requires Trusted Types and doesn't allow the checkpoint-beacon policy that beacon 1.4.3 and later create. ok when the beacon's policy is allowed.
proxy preflightinfo when the endpoint is on the page's origin. Otherwise it sends an OPTIONS request with Access-Control-Request-Method: POST and the beacon's headers, and reports ok, warn for a private endpoint, or fail when it's unreachable. It doesn't check KYA-Posture headers
posture, posture origin, posture key, posture projectinfo (not checked: <reason>) when you're not signed in, the project can't be resolved, or Vouched KYA doesn't serve posture. Otherwise: whether the page's origin may carry posture (fail for an http page, with the fix Browser posture needs an https page origin, and for an origin that isn't allowed, with a fix that runs kya-os detect install ... --origins '<list>'), whether the keys endpoint serves the project's key, and whether the page's beacon uses the project you compared (warn on a mismatch only). The posture checks run even when no beacon is found.

The doctor does not run the application. In a browser, confirm that initial API requests proceed before a token exists, later requests carry current posture headers, the API allows the required CORS headers, and the server reports the verified outcome. Repeat after reload and a session change. A zero exit code does not establish these runtime checks or load capacity.

login, logout, whoami, projects

CommandFlags
kya-os login--device, --project <id or name> (an ID is preselected on the consent page; a new name is offered for creation), --origin <url>, --json
kya-os logout--json. Revokes the session on Vouched KYA first; if Vouched KYA can't confirm, the local copy is kept.
kya-os whoami--json. Exits non-zero when nobody is signed in.
kya-os projects list--json
kya-os projects use <id or name>--json. Writes .kya-os/project.json where the nearest link already is, otherwise at the repository root.

The sign-in is a management session for a person. It lists your projects and links repositories to them, and Vouched KYA'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 Vouched KYA. 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.

FlagEffect
--project <id or name>The project, when this repository isn't linked yet
--skip-installScaffold without installing the server's dependencies
--dry-runPrint the scaffolder command and run nothing
-y, --yesMint the server's key without asking
--no-keyScaffold without minting a key
--jsonPrint one JSON document on stdout

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.local or .env. If the key is only in your shell's CHECKPOINT_API_KEY, install saves 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, install mints one.
  • Origin: the hook reports only to the Vouched KYA origin it was installed for (hook post --origin …), so a later edit to the committed link can't redirect the key.
FlagEffect
--agent claudeThe agent to hook (Claude Code)
--scope localDefault. .claude/settings.local.json: you only, gitignored, pinned to this binary
--scope project.claude/settings.json: everyone who clones the repository, so each needs kya-os on their PATH
--scope user~/.claude/settings.json: every repository you open; reports only from linked ones
--dry-run, --yes, --jsonAs for setup

Your other hooks and settings are kept, and a second install changes nothing, unless the hook points at another Vouched KYA origin 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:

  1. the --project flag;
  2. the KYA_OS_PROJECT environment variable;
  3. the nearest .kya-os/project.json, from the current directory up to the repository root;
  4. 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

VariableEffect
KYA_OS_PROJECTSelects the project, after --project
CHECKPOINT_API_URLThe Vouched KYA origin the CLI signs in to (default https://kya.vouched.id). The CLI reads it from its own environment; the SDK setting of the same name lives in your app's env file.
CHECKPOINT_PROXY_KEYThe forward-only key your proxy sets as X-API-Key. --proxy writes it to .env.local (Next.js) or .checkpoint-proxy.env, and it belongs in your host's environment too.
MCPI_CHECKPOINT_CONFIG_PATHWhere the CLI keeps its sign-in metadata (default ~/.mcpi/checkpoint.json)

The installer's own variables are on Installation.

Files

FileWhereHoldsCommit it?
.kya-os/project.jsonyour repositoryThe project link: origin, organization, project ID and name. No secret.Yes
.env.local or .envyour appCHECKPOINT_API_KEY and CHECKPOINT_PROJECT_ID, written by detect install --surface sdk (a minted key) or kya-os checkpoint key setNever
~/.mcpi/checkpoint.jsonyour home directorySign-in metadata. The tokens themselves are in the OS keychain: Keychain on macOS, the Secret Service on Linux.Not in a repository
~/.kya-os/bin/kya-osyour home directoryThe CLI, from the curl installerNot in a repository
checkpoint-detect.tsx or checkpoint-detect.jsNext.js layout directory or application entry directoryBrowser initialization and the per-request checkpointPostureHeaders() export. Next.js App Router and Vite HTML are wired automatically; other Node apps need the printed client importYes
checkpoint-beacon-assets.cjsapplication rootCopies companion assets from the installed beacon before the application's build, dev, and typecheck scripts, which keep their original commands as checkpoint:* scriptsYes
checkpoint-beacon-assets.jsonbeside the generated client moduleCurrent worker and lazy-signals URLs, rewritten by asset synchronizationYes
_checkpoint/<version>/your static directoryPackage installs copy the worker and lazy chunk from the installed npm version. Pinned-script installs use verified tarball files and also copy the script with --proxyYes
checkpoint-beacon-proxy.ts, middleware.ts or proxy.tsyour Next.js appThe beacon proxy, from --proxyYes
.checkpoint-proxy.envyour app, non-Next.jsCHECKPOINT_PROXY_KEY, from --proxy (Next.js uses .env.local)Never
.claude/settings.local.jsonyour repositoryThe govern hook, with --scope localNever (gitignored)
<server>/.dev.varsa server from mcp createThe server's CHECKPOINT_API_KEY for wrangler devNever (gitignored)
.kya-os/project.json
{
  "schema": "kya-os.project-link.v1",
  "origin": "https://kya.vouched.id",
  "organizationId": "5b1f3a9e-…",
  "projectId": "9c2d7e41-…",
  "name": "acme-web"
}

A link that names another Vouched KYA 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": ["…"]
    }
  }
}
FieldValues
link.statewritten, unchanged, wouldWrite (dry run)
detect.statusapplied, upToDate, planned (dry run), needsConfirmation (no terminal and no --yes), declined, skipped (--skip-install)
runtimeKeyPresent when a key was minted: its keyId, name, preview, and the file it was written to. Never the key.
detect.report.outcomes[].outcomeapplied, alreadyPresent, skipped, manual (with a title and snippet to add by hand), failed (with an error)

Exit codes

CodeMeaning
0Success, including a dry run
1An error: a failed step, a run that installed nothing, a plan left unapplied because there was no terminal and no --yes, a project that doesn't resolve, nobody signed in (whoami, projects), a detect doctor check that failed, browser posture that isn't fully set up (not signed in, unavailable, no usable page origin, key not confirmed, additional origins that couldn't be saved, or no verifier config for --surface sdk; the report prints first, and --dry-run never fails for these), or a --surface beacon install when the latest published beacon is older than 1.4.3
2A usage error: an unknown flag or a missing argument