@kindgi/cli
npm install @kindgi/cli · source
The kindgi command: create a Kindgi pack, run it on your machine while you
write it, build and deploy it, and work with a running Kindgi API (runs,
agents, tools, providers, approvals, …) from the terminal.
Install
Section titled “Install”The CLI is project-local: a project depends on @kindgi/cli as a
devDependency and runs the kindgi it pins, never a global install.
kindgi init adds it for you.
npx @kindgi/cli init # in an existing app, or: init <pack-name>pnpm installpnpm exec kindgi dev # npm: npx --no kindgi devUse the scoped name, @kindgi/cli: there is no unscoped kindgi package.
Requirements: Node 22 or later, and Docker for kindgi dev (Docker
Desktop, or a Docker engine on Linux). A Python pack also needs Python and
the kindgi Python SDK.
The pack lifecycle
Section titled “The pack lifecycle”| Command | What it does |
|---|---|
kindgi init |
Scaffold a pack, or add Kindgi to an existing app. |
kindgi dev |
Run the Kindgi runtime as a container, with your pack's code on your machine, re-indexed on every save. |
kindgi test |
Run the pack's tests with its own vitest. |
kindgi build |
Bundle, build and sign a pack image; writes deploy-envelope.json. |
kindgi deploy |
Send the signed envelope to POST /v1/deployments. |
kindgi env |
Per-environment values, kept in env files next to the pack. |
kindgi secrets |
Per-environment secrets, through the API. |
kindgi key |
Local Ed25519 signing keys under ~/.kindgi/keys/. |
kindgi skills |
Refresh the Claude Code skills in .claude/skills/. |
kindgi mcp |
MCP servers for your coding agent, in .mcp.json. |
kindgi feedback |
Note framework friction in the pack's FEEDBACK.md. |
The rest of the commands talk to a running Kindgi API: see API commands.
Quick start
Section titled “Quick start”pnpm exec kindgi init my-pack --template=samplecd my-pack && pnpm installpnpm exec kindgi devThen, from another terminal in the pack directory (kindgi dev writes the
API URL and token to .kindgirc.json there, so every command run in the
pack talks to it):
pnpm exec kindgi runs start --agent=my-pack.echo-agent --input='{"userMessage":"hi"}'pnpm exec kindgi runs start --flow=my-pack.echo-flow --input='{"name":"Ada"}'pnpm exec kindgi runs start --flow=my-pack.echo-flow --input='{"name":"Ada"}' --dry-runkindgi init
Section titled “kindgi init”kindgi init [<pack-name>] [--template=minimal|sample|python] [--path=<dir>] [--force] [--link-local] [--new-repo] [--pack-id=<id>]Three modes:
-
kindgi init <pack-name>scaffolds a new pack: the standard folders, akindgi.config.ts, starter primitives, tests and a README. -
kindgi initin a directory with apackage.jsonadds Kindgi to that app: akindgi.config.ts, akindgi/folder for the pack's primitives, the skills under.claude/skills/, and.gitignoreentries. It creates no env files:kindgi devreads the app's own.env/.env.local.--new-reposcaffolds a separate pack inside the app instead. -
kindgi initin a directory with apyproject.tomland nopackage.json(or--template=pythonwhere both are) adds a Python pack to that app, editing itspyproject.tomlin place and checking each edit by parsing the file again:- the
[tool.kindgi]tables: the pack id from[project].name(normalized;--pack-idoverrides), discovery underkindgi/, and for a Poetry appdev.python = ["poetry", "run", "python"]; kindgiin[project].dependencies. Where the dependencies can't be edited that way (Poetry 1,dynamic), it prints the command to run instead;[tool.uv] required-version, unless the app sets its own.
Plus
kindgi/{tools,guardrails,agents,flows}/, the Python-pack skills and.gitignoreentries. The next steps it prints follow the app's installer: uv, Poetry or pip. - the
A Node project gets @kindgi/sdk (a dependency) and @kindgi/cli (a
devDependency) at the running CLI's own version, or linked from a checkout
(--link-local); never latest.
| Flag | Purpose |
|---|---|
<pack-name> |
The pack id: lowercase kebab-case, optionally dot-namespaced (my-pack, acme.legal-basics). |
--template=<name> |
minimal (the default: the folders, no examples), sample (three tools, a guardrail, an agent and a flow), or python (the sample as a Python pack). |
--path=<dir> |
Where to scaffold. Default: <pack-name> under the current directory (for a dot-namespaced id, its last segment). |
--force |
Write into a non-empty directory. Default: refuse. |
--link-local |
Link @kindgi/* from the checkout the CLI runs from. |
--new-repo |
In an existing app: scaffold a separate pack rather than adding Kindgi to the app. |
--pack-id=<id> |
Adding to an app: the pack id, when the app's name doesn't make a valid one. |
Skills
Section titled “Skills”init copies the @kindgi/sdk skills into .claude/skills/, so a coding
agent working in the pack knows how to write tools, agents, guardrails,
flows and providers. A pack gets the skills written for its language: a
TypeScript pack the TypeScript ones, a Python pack the kindgi-python-*
ones, both the shared ones. kindgi skills sync refreshes them, and
.claude/skills/.kindgi-manifest.json records what was installed.
kindgi dev
Section titled “kindgi dev”kindgi dev [--port <n>] [--database-url <url>] [--tenant <id>] [--dev-token <token>] [--no-watch] [--path <dir>] [--reset] [--recreate-services] [--runtime-image <ref> | --runtime-url <url>]One command runs the whole loop on your machine:
- The Kindgi runtime runs as a container (
docker run), one per pack directory, with the pack directory mounted at/pack. Its API is published on127.0.0.1only. - Your pack's code runs on your machine, in a local pack service: the
same process a deployment runs, with your Node or Python, your
node_modulesor virtualenv, and your app's modules. The runtime calls it for every tool and guardrail check. - Postgres: a bundled Postgres, started with
docker compose(thekindgi-devproject, shared by everykindgi devon the machine and left running), or the one you name with--database-url/KINDGI_DATABASE_URL. - The pack is indexed and watched.
kindgi devfinds every tool, guardrail, agent and flow, and on each save re-indexes, rebuilds the code and restarts the pack service. The next request sees the new definitions; a run already in flight keeps the version it started with.
| Flag | Purpose |
|---|---|
--port=<n> |
The port the API is reached on, on 127.0.0.1. Default 4000. |
--database-url=<url> |
The Postgres to use. Falls back to KINDGI_DATABASE_URL (the shell's, then the env files'). Without either, the bundled Postgres. |
--tenant=<id> |
Pin the tenant. Default: the previous run's (from .kindgirc.json), else a new one. The pack's primitives and registered providers stay with it. |
--dev-token=<token> |
Pin the API token. Default: the previous run's, else a new one. Each flag overrides only its own value: --dev-token alone keeps the tenant. |
--path=<dir> |
The pack root. Default: the current directory. It must have a kindgi.config.ts, or a pyproject.toml with a [tool.kindgi] table. |
--no-watch |
Start, index once, and exit. For smoke tests and CI. |
--reset |
Start this pack fresh: removes .kindgirc.json, so the boot makes a new tenant and token and the pack sees none of its earlier data. The bundled Postgres, which every pack on the machine shares, is left alone. (To wipe all dev data: docker compose -p kindgi-dev down -v.) |
--recreate-services |
Let docker compose recreate the bundled Postgres if its definition changed. By default an existing container is reused as it is, so no other kindgi dev loses its database. |
--runtime-image=<ref> |
The runtime image to run. Default: the one this CLI release was tested with. |
--runtime-url=<url> |
Use a runtime you run yourself instead of starting the container. Start it with the pack's .kindgi/dev/runtime.env. |
The runtime container
Section titled “The runtime container”- Configuration: everything the runtime is told is written to
.kindgi/dev/runtime.env(mode0600) and passed withdocker run --env-file. The runtime reads nothing else from your machine. - Your machine's
localhost: calls the runtime makes tolocalhost(your app'srun.finishedwebhook, an MCP server, a model server you run locally) reach your machine. On Docker Desktop they go throughhost.docker.internal. On Linux the container shares the host's network and runs as your user, so files it writes into the pack stay yours. - Google Cloud credentials: for Vertex AI models, your Application
Default Credentials file (
GOOGLE_APPLICATION_CREDENTIALS, else the onegcloud auth application-default loginwrites) is mounted read-only. Kindgi keeps no key files of its own. - The image: the runtime image is pulled on first use. It is in
private preview: request access at contact@kindgi.com, then
docker login quay.iowith the pull credentials you receive.kindgi devsays so when a pull is refused.
Env files
Section titled “Env files”kindgi dev runs as the local environment and reads the project's own env
files at the pack root: .env, then .env.local on top, parsed the way the
application beside the pack parses them (dotenv grammar, ${VAR}
expansion). Nothing is copied: a key already in the app's .env is available
to the pack.
-
KINDGI_*names configure Kindgi itself (e.g.KINDGI_DATABASE_URL). Precedence: flag > shell > env files. -
Every other name belongs to the pack: providers, tools and MCP servers resolve them as secrets.
KINDGI_*names never resolve as secrets, so the app's ownDATABASE_URLstays the app's. -
Writes (
kindgi secrets set,kindgi env set --env=local) go to the highest-precedence file (.env.local), and every other line is kept. Kindgi never edits a lower file such as the app's.env. -
Different files? List them, lowest precedence first, and restart
kindgi dev:export default {pack: { id: 'acme.app', version: '1.0.0' },dev: { envFiles: ['.env', '.env.development', '.env.local'] },};
The startup output names the files it found and how many names they give the
pack. A malformed line is reported as file:line, never its text.
The names the pack's code reads. Declare them in kindgi.config.ts:
export default { pack: { id: 'acme.app', version: '1.0.0' }, env: { required: ['DATABASE_URL'], optional: ['LOG_LEVEL'] },};A required name the env files don't give gets a warning in kindgi dev, which
keeps serving. A deployed pack service isn't ready without it, and says which
names it lacks. A deployment injects exactly the declared names.
Model providers
Section titled “Model providers”A tenant with no providers gets dev-echo, a fallback provider (scripted
replies, no key, no network) that answers only while no other provider fits.
Agent turns run before you register a model, and registering one takes over
with nothing to switch off:
kindgi providers register --preset=anthropic # the key must be in the env fileskindgi providers register --preset=gemini --project=<gcp-project>A turn the fallback answers carries a fallback-provider warning, which
kindgi runs start prints. kindgi providers unregister dev-echo removes it
for good.
Any OpenAI-compatible endpoint — an open-source model you serve yourself
(vLLM, llama.cpp's llama-server, Ollama, LM Studio), OpenRouter, a LiteLLM
proxy — registers with --spec, naming its base URL in adapter_config:
{ "adapter_id": "@kindgi/adapter-model-openai-compat", "adapter_config": { "baseURL": "http://127.0.0.1:8000/v1" }, "metadata": { "id": "qwen-local", "region": "unspecified", "models": [{ "name": "qwen3.5-4b", "contextWindow": 32768, "features": ["tool-use"], "cost": { "promptUsdPer1kTokens": 0, "completionUsdPer1kTokens": 0 } }] }}kindgi providers register --spec=@qwen.json, then point an agent at it
(preferred_provider="qwen-local"). An endpoint that needs a key takes a
secret_ref ({ "envName": "local", "name": "MY_KEY" }), resolved on every
call. The model must call tools in the OpenAI format: serve it with tool
calling on (vLLM --enable-auto-tool-choice --tool-call-parser <model's>,
llama-server --jinja) and, for a thinking model such as Qwen, thinking off: on the server
(vLLM --default-chat-template-kwargs '{"enable_thinking": false}', llama-server --reasoning off),
or, for a shared server you can't reconfigure, per request from the provider row:
"extraBody.chat_template_kwargs.enable_thinking": false in adapter_config (one flat key per
request field; dots nest).
What you see
Section titled “What you see” ✓ Kindgi is up API http://127.0.0.1:4000 Console http://127.0.0.1:4000/console/ Tenant c9a4… Token kgi_bt_… Providers dev-echo (fallback) — … Origins …
Try it (from another terminal, cd to the pack dir first): pnpm exec kindgi runs start --agent=my-pack.echo-agent --input='{"userMessage":"hi"}' pnpm exec kindgi runs stream <run-id>
Watching /path/to/my-pack Ctrl+C to stop.Progress and the runtime's own log lines ([runtime] …, [pack] …) go to
stderr; a JSON summary goes to stdout, so kindgi dev --no-watch --raw | jq
works.
Watching
Section titled “Watching”kindgi dev watches the pack's discovery patterns from kindgi.config.ts
(default tools/, agents/, guardrails/, flows/; an app with Kindgi
added watches kindgi/), and the env files. Only each pattern's fixed
directory is watched, never the whole app. The dev index lives at
.kindgi/dev/index.json.
- An empty pack is not an error: the output says where to add the first primitive.
- A file that fails to index or build (a bad schema, a missing default export, a syntax error) is reported with its path and the error, and the previous code keeps serving until you fix it and save.
- Deleting a primitive's folder removes it from the catalog.
A Python pack
Section titled “A Python pack”A pack whose config is the [tool.kindgi] table of its pyproject.toml is a
Python pack: its tools and guardrail checks are Python, its agents and flows
data. kindgi dev runs it the same way, with the pack's own interpreter:
- The interpreter:
dev.pythonin[tool.kindgi](a path, or a command such as["uv", "run", "python"]), else the pack's.venv/bin/python, elsepython3. It must importkindgiwith the pack's environment, orkindgi devstops and says how to install it. - Build: every
.pyfile under the pack root is compiled; a syntax error is reported asfile:line:coland the previous code keeps serving. - Index and serve:
python -m kindgi.pack index, thenpython -m kindgi.pack servein the pack service. The runtime can't tell it from a Node pack. - Watch: any
.pyfile under the pack root (shared modules included) andpyproject.toml. - The CLI: a Python pack has no npm project, so it runs the published
CLI through npx (Node 22 needed):
npx --yes @kindgi/cli@0.1 <command>, within the CLI's minor, in the startup hints and in the.mcp.jsonentrieskindgi mcp addwrites.
Stopping
Section titled “Stopping”Ctrl+C (or SIGTERM) stops the watchers, the pack service and the runtime
container. The bundled Postgres keeps running for the next kindgi dev.
The exit code is 0 after a clean stop and 1 if startup failed.
kindgi test
Section titled “kindgi test”kindgi test [--watch] [--reporter <name>] [--path <dir>] [-- <vitest-args>...]Runs the pack's tests with the pack's own vitest (the CLI bundles none, so the
pack chooses its vitest version). The templates include a vitest.config.ts
and a first test. --watch runs vitest in watch mode; everything after --
goes to vitest as is. The CLI refuses to run without a vitest.config.* at
the pack root, and uses pnpm exec vitest in a pnpm project, else
npx --no-install vitest.
kindgi build
Section titled “kindgi build”kindgi build [--local [--push [<repository>]] [--platform <os/arch>]] [--env <name>] [--endpoint <url>] [--target <t>] [--out <dir>] [--artifact-version <v>] [--published-at <iso>] [--tenant <id>] [--signing-key <path>] [--registry-push-creds <ref>] [--skip-integrity-gate] [--skip-image-pull] [--skip-sign] [--path <dir>]Builds a signed pack image with a Kindgi build server, and writes
deploy-envelope.json for kindgi deploy:
-
Config: reads
kindgi.config.tsand the--envblock (defaultstaging): the build server, the tenant and the signing key. -
Bundle: bundles every primitive and the config with esbuild, each
.mjswith a sourcemap. The pack's own code, and the app code it imports, is bundled; the app's installed dependencies stay external, imported by name from the image'snode_modules. The pack service and the indexer are self-contained bundles. A Python pack ships its source and lockfile instead. -
Index: runs the bundled indexer over the bundles locally, into
expected-index.json, exactly as the image's indexer stage will. -
Containerfile and context: writes a multi-stage
Containerfileand the build context:- what the install reads:
package.json, the lockfile, every workspace member'spackage.json, the workspace file, patches, and tarballs vendored in the project; - the bundles;
- what
bundle.includelists.
The pack's source never ships. Env files,
.kindgirc.json, private keys and anything under.git/,.kindgi/ornode_modules/are refused: a build that would ship one fails and names it..npmrcand.yarnrc*are read by the install as build secrets, never copied into the image. - what the install reads:
-
Build: uploads the context (
pack.tgz) to the build server and streams its log. -
Integrity gate: the image's index must match the local one, byte for byte (
--skip-image-pullcompares hashes only, without pulling the image). -
Sign and write: signs the image digest and index hash with your Ed25519 key and writes
.kindgi/build/deploy-envelope.json.
The image (a TypeScript pack):
- Base:
node:22ornode:24-bookworm-slim, pinned by digest: the first whose Node satisfies the app'sengines.node. - Install: the app's dependencies, installed the way the app installs
them, from its own lockfile, frozen. pnpm and yarn come through corepack
and the
packageManagerfield. Build scripts are off during the install; thenrebuildruns the ones the app allows, and the install is pruned to production dependencies. - A workspace: with pnpm, only the pack's project and what it depends on are installed, not the rest of the workspace. npm and yarn install the whole workspace.
- Layout: the lockfile's folder is
/app, and a pack inside a workspace member sits at its own path. - Runs: the pack service, under tini, as
node, on$PORT(8080).
A dependency linked from outside the project (link:../…, file:/…) can't be
installed in an image: vendor it as a tarball inside the project
(file:vendor/<name>.tgz) or install it from a registry.
What the image needs beyond the install goes in image, with
@kindgi/sdk/build:
import { prisma } from '@kindgi/sdk/build';
export default { pack: { id: 'acme.app', version: '1.0.0' }, image: { systemPackages: ['tesseract-ocr'], // Debian packages extensions: [prisma({ schema: 'prisma/schema.prisma', config: 'prisma.config.ts' })], buildEnv: { DATABASE_URL: 'postgresql://build-placeholder' }, },};systemPackagesare installed in the base image.prisma()copies the schema (and config) into the image and runsprisma generateafter the install, before the prune. The app's ownpostinstalldoesn't run in the image, because the install runs with scripts off.buildEnvholds non-secret placeholders for the build steps, and for the indexer, which imports the pack's modules. It's never in the final image.defineBuildExtension()makes an app's own extension from the same parts:contextFiles,systemPackages,postInstallsteps (a package's bin, run through the app's package manager) andbuildEnv.
--local: builds the image with this machine's Docker
(docker buildx build --load) into its image store, as
kindgi-pack/<packId>:<artifactVersion>, with the same integrity gate. There
is no build server, signature or envelope, and no tenant or signing key
needed. It prints a docker run line.
--local --push: publishes from this machine, for kindgi deploy:
- builds the image for the deployment's platform:
linux/amd64by default, which Cloud Run runs (on Apple silicon, under emulation);--platformoverrides it; - pushes it to
<repository>:<artifactVersion>. The repository is--push's value, elseenvironments.<env>.registry+/<packId>; - pulls it back by digest for the integrity gate;
- signs it as the build service path does, and writes
.kindgi/build/deploy-envelope.json.
It uses your own Docker credentials for the registry, for example
gcloud auth configure-docker <region>-docker.pkg.dev for Artifact Registry.
Kindgi holds none. It needs the env block's tenantId and signingKey, or
--tenant and --signing-key.
Files a tool reads at runtime, rather than imports, go in bundle.include:
export default { pack: { id: 'acme.app', version: '1.0.0' }, bundle: { include: ['kindgi/data/**/*.json'] },};A Python pack: the image is python:3.13-slim-bookworm with uv, both pinned by
digest, and the pack's dependencies come from its lockfile (uv.lock, or a
Poetry app's poetry.lock; one is required). Debian packages the code needs
go in [tool.kindgi.image] system-packages = ["tesseract-ocr"]. The image's
uv version must be in the pack's [tool.uv] required-version; kindgi build stops before uploading when it isn't.
Reproducible: the build pins SOURCE_DATE_EPOCH=0, the publish time
(--published-at, default the epoch) and the artifact version
(--artifact-version, default YYYYMMDD.1), and the base images by digest,
so the same inputs give the same image.
| Flag | Purpose |
|---|---|
--local |
Build with this machine's Docker instead of a build server: no signing, no envelope. TypeScript packs. |
--push[=<repository>] |
With --local: push the image, sign it, and write the envelope. Default repository: the env block's registry + /<packId>. |
--platform=<os/arch> |
The image's platform. Default: linux/amd64 when pushing, else this machine's. |
--endpoint=<url> |
The build server. Default: the env block's build. |
--tenant=<id> |
The tenant the signature names. Default: the env block's tenantId, else KINDGI_TENANT_ID. |
--signing-key=<path> |
The Ed25519 private key (PEM). Default: the env block's signingKey. |
--skip-integrity-gate |
Sign without re-checking the image's index. Prints a warning. |
--skip-sign |
Write an unsigned envelope (for CI that signs elsewhere); kindgi deploy refuses it. |
kindgi deploy
Section titled “kindgi deploy”kindgi deploy [--env <name>] [--from-envelope <path>] [--endpoint <url>] [--token <bearer>] [--tenant <id>] [--idempotency-key <str>] [--dry-run] [--sync-secrets] [--allow-missing-env] [--path <dir>] # plus kindgi build's flags, used when there is no envelope yetSends the signed envelope to POST /v1/deployments and prints the
deployment. The envelope is --from-envelope, else
.kindgi/build/deploy-envelope.json, else kindgi deploy runs
kindgi build first (--build-endpoint is the build server there, since
--endpoint is the API).
- The API:
--endpoint, else the env block'sendpoint, else--url/KINDGI_API_URL. - Idempotent: the
Idempotency-Keyheader is a hash of the request body (--idempotency-keyoverrides it). Deploying the same image again returns the same deployment. --tenantmust match the envelope's tenant, checked before anything is sent.--dry-runprints the equivalentcurlcommand and sends nothing.- The pack service's env, checked first. When the pack declares
env, the deploy prints the plan for--env(seekindgi env plan). It refuses when a required name has no value or reference inenvironments.<env>.env(--allow-missing-envdeploys anyway, with a warning), or when a secret is given in the clear. That case has no override. --sync-secretsalso sends the values in.env.<envName>to the deployment's secrets after it lands. Off by default; without it, a deploy with such a file says what it didn't send. With it, secret-shaped names (*_KEY,*_TOKEN,*_SECRET, …) get a warning: those belong inkindgi secrets set.- Errors carry a hint for the common ones:
signature-invalid,signer-not-trusted,image-unverifiable,deployment-validation-failed.
kindgi env
Section titled “kindgi env”kindgi env list [--env <name>] [--reveal] [--force-reveal] [--path <dir>]kindgi env set <KEY> <VALUE> [--env <name>] [--force] [--path <dir>]kindgi env unset <KEY> [--env <name>] [--path <dir>]kindgi env pull [--env <name>] --scope=<kind>[:id] [--overwrite-existing] [--path <dir>]kindgi env init [--secrets-backend=<none|postgres|secret-manager>] [--kms=<gcp|aws|libsodium|vault>] [--out=<path>]kindgi env plan [--env <name>] [--format=terraform|gcloud] [--path <dir>]Per-environment values for the pack, in env files next to
kindgi.config.ts. --env defaults to staging.
-
--env=localis the project's own env files, the oneskindgi devreads (.env<.env.local, ordev.envFiles).listshows the merged view and which file each key came from;setandunsetedit only the highest-precedence file, and say so when a lower file (the app's.env) still defines the key. -
Any other env is
.env.<envName>, the filekindgi deploy --sync-secretssends. -
listredacts values;--revealprints them, but not to a pipe without--force-reveal. -
pullfetches the env's values from the API into.env.<envName>. -
initwrites a.env.examplefor a deployment target. -
Format: dotenv, read the way
dotenv(and Next.js) read it, with${VAR}expansion.setandunsettouch one key and keep every other byte. -
KINDGI_*names are refused: they configure the runtime and belong in its environment, not the pack's. -
planshows the process env a deployed pack service gets in--env: each name the pack declares (env.required/env.optional) and its source inenvironments.<env>.envinkindgi.config.ts. A source is a plain value, or a Secret Manager reference that the platform resolves with the pack service's own identity (Kindgi never sees the value):environments: {production: {env: {LOG_LEVEL: 'info',DATABASE_URL: { secret: 'acme-db-url', version: '3' },// a secret in another project, named by project number:SHARED_TOKEN: { secret: 'shared-token', version: '2', project: '123456789012' },},},},It prints the Terraform input (
envandsecret_env), or with--format=gcloudthe--set-env-vars/--set-secretsflags. It exits 1 when a required name has no source, or when a secret is given as a plain value: by its name (*_KEY,*_TOKEN, …) or by a credential in it (a URL with a password). That value is never printed. A reference to versionlatestis read when an instance starts, so a new version needs a new revision.
kindgi secrets
Section titled “kindgi secrets”kindgi secrets list|get|set|rotate|revoke|pull --env=<name> --scope=<kind>[:id] …Secrets through the API's /v1/secrets routes. Values are never printed and
never returned: list and get show metadata only, and pull writes a
manifest (.secrets/<envName>/manifest.json), not the values. set and
rotate read the value from a no-echo prompt, --from-stdin or
--from-file (a file others can read is refused). revoke keeps an audit
tombstone; --hard erases the value. Under kindgi dev, --env=local
writes to the pack's .env.local.
kindgi key
Section titled “kindgi key”kindgi key create <keyId> [--env <name>] [--home <dir>]kindgi key export <keyId> [--format=pem|base64|raw-hex] [--home <dir>]kindgi key list [--home <dir>]Ed25519 signing keys for kindgi build, as files under ~/.kindgi/keys/
(the directory 0700, <keyId>.pem 0600, <keyId>.pub.pem 0644).
creategenerates a key pair and refuses to overwrite an existing one. With--env, it prints what to add to that env block inkindgi.config.ts.exportprints the public key only, never the private one.listshows each key pair's id, fingerprint and paths.
kindgi skills
Section titled “kindgi skills”kindgi skills sync [--force] [--dry-run] refreshes .claude/skills/ from the
skills bundled with this CLI. Skills you edited are kept unless --force.
kindgi dev mentions it when the installed skills are behind.
kindgi mcp
Section titled “kindgi mcp”MCP servers for your coding agent (Claude Code, Cursor, VS Code, …), not for the runtime:
kindgi mcp presetskindgi mcp add postgres --secret=MY_DB_URLkindgi mcp listkindgi mcp remove <server-name>add writes an entry to .mcp.json at the pack root. The entry runs
kindgi mcp-launch, which starts the MCP server with the secret from the
pack's env files in its environment, so the secret is never written into
.mcp.json. The kindgi-authoring-mcp-servers skill covers the details.
kindgi feedback
Section titled “kindgi feedback”kindgi feedback write --kind=bug --title="…" appends a note about framework
friction to FEEDBACK.md at the pack root, where a coding agent can leave
what it diagnosed for the maintainers.
API commands
Section titled “API commands”These call a running Kindgi API through @kindgi/client.
Inside a pack that kindgi dev runs, they find it on their own (see
Auth and config).
| Command | Subcommands |
|---|---|
runs |
list, get, cancel, journal, stream (one JSON event per line), start, resume |
agents |
publish |
tools |
list, get, unregister, versions, get-version, reinstate |
guardrails |
list, get, register, unregister |
providers |
list, get, register, presets, unregister |
adapters |
prepare |
approvals |
list, get, complete |
reviewers |
list, get, register, unregister |
health |
GET /health, no auth |
version |
The CLI's and SDK's versions, and the API's when it's reachable |
kindgi runs start starts a run for an agent (--agent=<id>) or a flow
(--flow=<id>) and waits for it to finish. --no-wait prints a flow run as
soon as it exists and lets it finish in the background (follow it with
runs get or runs stream); an agent run always answers when its turn ends.
--dry-run runs only the tools declared read-only (mutating: false).
kindgi <command> --help prints a command's subcommands and flags.
More of the API (memory, artifacts, provenance, conversations, proposals,
observations, tokens, capabilities, and listing agents and flows) has
commands in progress. They're left out of --help until they work; until
then, use @kindgi/client for those resources.
Auth and config
Section titled “Auth and config”The API URL and token come from, in order:
| Source | API URL | Token |
|---|---|---|
| Flag | --url |
--token |
| Environment | KINDGI_API_URL |
KINDGI_API_TOKEN |
.kindgirc.json in the current directory |
apiUrl |
token |
~/.kindgi/config.json |
apiUrl |
token |
kindgi dev writes .kindgirc.json in the pack. For another API, save the
pair once with kindgi auth login --url=<url> --token=<token>, and check it
with kindgi auth whoami.
Output and global flags
Section titled “Output and global flags”| Flag | Effect |
|---|---|
--json |
Pretty JSON on stdout (the default), for jq. |
--raw |
One-line JSON. |
--table |
A table for list responses (JSON where a list has no columns). |
--quiet |
Nothing on stdout; the exit code only. |
--url=<url>, --token=<token> |
The API and its token (see above). |
--verbose, -v |
Full errors: stack traces and the API's error bodies. |
--version |
The CLI's version. |
--help, -h |
Help for the CLI or a command. |