Kindgi 0.1.8
Released October 16, 2026. For the docs of this version, see docs.kindgi.com/v0.1.8.
Security fixes
Section titled “Security fixes”- A key limited to a project could file a conversation outside it. A
conversation started with a key limited to a project (
--project) that named no project was filed in the tenant's default project, not the key's: the key couldn't read it afterwards, and the default project's readers could. A run continuing that conversation was filed there too. In 0.1.8 a conversation that names no project goes to the key's project, and a key can't continue a conversation outside its project (403 key-project-mismatch). 0.1.5 to 0.1.7 are affected (API keys). - Some clouds' metadata addresses weren't refused. Kindgi refuses a
cloud's metadata address wherever tenant configuration names a host (at
KINDGI_TENANT_HOST_ACCESS=deployedand above) and in a webhook's URL outside development mode. Before 0.1.8 it refused only link-local addresses and AWS's IPv6 one, not the others that clouds document: Azure's WireServer (168.63.129.16), Alibaba Cloud's metadata service (100.100.100.200), the EKS Pod Identity Agent (fd00:ec2::23), Compute Engine's for IPv6-only VMs (fd20:ce::254), Akamai's (Linode's,fd00:a9fe:a9fe::1) and Scaleway's (fd00:42::42). Azure's counted as a public address, so a host or a webhook could name it at every level; the others counted as private, so a host could name them atdeployed, and a webhook underKINDGI_WEBHOOK_PRIVATE_NETWORKS=allow. In 0.1.8 they're refused wherever link-local addresses are, and an IPv4 address written inside an IPv6 one as IPv4-translated (::ffff:0:a.b.c.d) is read as that IPv4 address, as the other forms already were. These ranges, which no service is reached at, are refused too:192.88.99.0/24,2001:2::/48,2001:10::/28,3fff::/20,5f00::/16and100:0:0:1::/64. Every release before 0.1.8 is affected.- A webhook URL refused for a link-local or metadata address now says
"link-local and cloud metadata addresses are not allowed". Under
KINDGI_WEBHOOK_PRIVATE_NETWORKS=allow, the other refusals say "loopback and reserved addresses are not allowed", where they said "loopback, link-local and reserved addresses are not allowed". A script that matches the old words needs the new ones.
- A webhook URL refused for a link-local or metadata address now says
"link-local and cloud metadata addresses are not allowed". Under
- The S3-compatible routes read a whole upload before checking its
signature.
@kindgi/apiserves S3-compatible routes (/s3/*) to an app that embeds it and sets itss3Credentialsoption. They read a request's whole body into memory before they checked its signature, so a caller with no credentials could make the server hold a body of any size. Kindgi's runtime doesn't serve these routes, self-hosted or hosted. In 0.1.8 the signature is checked first, from the headers, and the body is read only up toartifactMaxBytes(100 MiB by default): a larger one is refused with S3's400 EntityTooLarge. A larger object goes up as a multipart upload, each part under the limit. A header-signed body is checked against itsx-amz-content-sha256when it's empty too.@kindgi/api0.1.8 needshono4.13.8 or later. - A tenant's policies were skipped when they couldn't be read. If
reading a tenant's policies failed, such as on a database error, the
tenant was treated as having none. A turn ran without its approval,
model-routing and tool-errors policies, and a removed model provider
that a retention policy keeps for good could be deleted with its
adapter. In 0.1.8 such a read fails instead: the turn fails, nothing
is deleted, and the policies API answers
500rather than an empty list. Every release before 0.1.8 is affected; the provider deletion, 0.1.4 to 0.1.7.
- Tenants that don't trust one another: a new level,
KINDGI_TENANT_HOST_ACCESS=isolated, is for a runtime whose tenants don't trust one another. It refuses all thatdeployeddoes, and also private networks wherever tenant configuration names a host. A model provider can't sign in with the runtime's own cloud credentials there: Gemini on Vertex AI needs a service-account key insecret_ref, and Bedrock'sauth: aws-identity(thebedrockpreset's default) and Azure OpenAI'sauth: entraare refused. The runtime won't start with it in development mode, or withKINDGI_WEBHOOK_PRIVATE_NETWORKS=alloworKINDGI_AUTH_PRIVATE_IDP_ORIGINS(What a tenant can't make the server do). - One runtime for many tenants: with
KINDGI_TENANCY=multi, a runtime serves every tenant created throughPOST /v1/system/tenants, and takes each request's tenant from its key or session. It starts only withKINDGI_TENANT_HOST_ACCESS=isolated, per-deployment routing, OpenFGA with a key, the production gate and usage metering, and a start without any of them names each. The deployment's own token reaches only/v1/system/*. A closed tenant can still export its data for 30 days, and is then purged, andkindgi-runtime tenants repair --allsets up what an upgrade adds for each tenant (Serve many tenants). - Memory limits for agent turns: two new runtime settings limit the
memory running agent turns hold, both off unless set:
KINDGI_TURN_MEMORY_PER_TENANT_MIBfor one tenant's turns, andKINDGI_TURN_MEMORY_MIBfor every tenant's together. A turn is charged by size before each model call. Past either limit, the turn fails before the model is called, with429 turn-memory-limit-reached(details.limitistenantorserver). Every tool call it finished stays in the conversation, so a new turn there doesn't call it again. A resumed run is charged its journal first, and one whose journal alone is past a limit fails with the same code. One that only finds no room yet waits: a top-level run goes back topending, first in line, until there is room; a flow's step is left to the lease sweeper, whose third try without room fails it (about 15 minutes at the defaultKINDGI_RUN_LEASE_MS). The startup log shows both settings when either is set (Environment variables). - A failed run's details:
- A failed run's
failurecan carrydetailswhen its code has them, wherever the run is read back:GET /v1/runs/{runId}, the runs list, and the answer to aPOST /v1/runsthat waited. Forrate-limit-exceeded,detailshaslimit(schema-compile-timeortemplate-render-time) andbudgetMs, the names the429uses. It never has the wait: the start's429gives it inRetry-After. Other codes, and runs from an older runtime, have nodetails. - A
run.finishedwebhook's run can carryfailure(code,message,causewhen set, anddetails) besidefailureMessage, which stays. It's there only when the run failed, and only from a runtime that sends it: readfailureMessagewhen it's absent.parseEvent(@kindgi/sdk/webhooks) reads it. - The run stream's
run.failedstill carries only the message. For the code anddetails, read the run (GET /v1/runs/{runId}).
- A failed run's
- A license renewal can send the deployment's use:
kindgi license renew --runtime <url> --runtime-token <ref>sends the deployment's use with a non-production key's renewal: counts only (runs started, people, projects in production, and the runtime's version), with no content, names or ids. access.kindgi.com keeps and reads them from the date on its privacy page. Without the two flags, a renewal carries none, as before (Renew the license key).- A renewal whose counts are above what a non-production key covers is
refused with
held-for-review, and gets no new key until Kindgi reviews it. GET /v1/license/usage?since=<time>answers those counts, for the deployment's own token or a system key holdingsystem:license.
- Coding agents:
kindgi initandkindgi skills syncwrite Kindgi's skills to.agents/skills/as well as.claude/skills/. Codex and Gemini CLI read skills from.agents/skills/. Each folder holds the same copy of each skill, andkindgi skills syncchecks each copy on its own: a copy you edited is kept unless you pass--force, and a folder you deleted is written again (Coding agents).kindgi skills syncprints its summary on stderr, one block per folder, unless you pass--jsonor--quiet. In its JSON, each outcome names itsfolder.- A
.prettierignoreyour project already has gets.agents/skills/kindgi-*/beside.claude/skills/kindgi-*/, fromkindgi initin an existing TypeScript app and fromkindgi skills sync, which never creates one. - The templates'
AGENTS.mdname both folders, and say which commands are yours to run in your own terminal.
- Kindgi Cloud, from the CLI:
kindgi build --hosted, or the env block'sbuild: 'hosted', builds your pack on Kindgi Cloud's build service.kindgi deploy --hostedbuilds and deploys it, then waits up to 5 minutes for its pack service to be ready. It signs with a key of yours (kindgi key create, thenkindgi key trustonce), named with--signing-keyor the environment'ssigningKey. - The CLI waits out a rate limit:
kindgi deploy,kindgi flows publish,kindgi agents publishandkindgi blocks publishwait out a429 rate-limit-exceededthat says when to try again (Retry-After), then send the same request again, printing one line on stderr for each wait. They wait 10 minutes at most in all. Past that, on a429withoutRetry-After, or when Ctrl+C stops a wait, they fail with the error, as before. A script that runs them can take up to 10 minutes longer to fail. - Read a run's journal a page at a time:
GET /v1/runs/:runId/journaltakeslimit(1 to 100) andcursor. Each page hashasMore, andnextCursorwhile more remain; in Python,runs.journaltakeslimitandcursor, and the page hashas_moreandnext_cursor. Withoutlimit, the whole journal comes in one answer, as before. Alimitthat isn't a whole number of 1 or more, or a malformedcursor, is400 bad-input.kindgi runs journal --limit --cursorand the TypeScript client took them already; a runtime before 0.1.8 answers the whole journal (Read a run's journal). - Check a restore's secrets:
kindgi-runtime check stored-secretsdecrypts each live version of every stored secret with the runtime's keys, and names by id each one that doesn't. Run it after a restore, before the runtime serves: a restore brings back the database, not the keys (Back up and restore). - Capabilities for a tenant's first admin: the person a tenant is
created with (
firstAdminonPOST /v1/system/tenants, and whoever signs up for Kindgi Cloud) holds every capability butsecrets:reveal: trusting signing keys, and writing secrets and environment values. Their sign-in sessions carry them, and the console's Create a key offers them under What it can change, so a key made there can trust signing keys and sync secrets (Who can do what).
- Authorization on a managed Postgres:
- With authorization on, a runtime whose database user has no
BYPASSRLS(and isn't a superuser), the usual case on a managed Postgres, now starts. On 0.1.6 and 0.1.7 it didn't (Known limitations in 0.1.7). - A runtime that shares its database with others brings only its own tenants' authorization stores up to the current model, and drains only their changes to OpenFGA.
- When the runtime can't read or update one tenant's part of the queue of permission changes it sends to OpenFGA, it logs an error and goes on with the other tenants. That tenant's changes apply on a later pass, with no restart (Run with authorization).
- With authorization on, a runtime whose database user has no
- Guardrails scoped to flows: a guardrail whose
scopelistsflowsnow checks the turns those flows' steps start, and replays of those turns. In 0.1.7 it never checked a turn: a turn didn't say which flow it ran in, so the guardrail skipped it without a word. Ahaltone can now stop turns that 0.1.7 let through. A turn outside those flows is still skipped (Which agents it covers). - Requests:
- An idempotency key compares request bodies byte for byte. A key limited
to a project that sent one
Idempotency-Keywith another body now gets409 idempotency-key-body-mismatch, and a binary upload sent with a key is stored as it was sent. - A key limited to a project can upload a run's artifacts. An upload that
names no project goes to the key's project, and one that names another
project is refused with
403 key-project-mismatch.
- An idempotency key compares request bodies byte for byte. A key limited
to a project that sent one
- Secrets: a secret the store can't take for its name or its value is
refused with a
400and a code that says why. It was a500 secret-store-error.- Under
kindgi dev, a name that isn't capital letters, digits and underscores, starts with a digit, or isKINDGI_*answerssecret-name-invalid, and a name starting withkindgi.answersreserved-name-prefix. That covers storing a secret, setting the tenant's configuration, and registering a webhook trigger that generates its secret, which is now refused before anything is stored. - Under
kindgi dev, a value no env-file quoting can hold so that it reads back unchanged answerssecret-value-invalid. The message doesn't repeat the value (Underkindgi dev). - With
KINDGI_SECRETS_BACKEND=postgres, a name starting withkindgi.answersreserved-name-prefix, and a value over the store's size limit answerssecret-value-too-large, as the in-memory store already did. - Rotating a secret in the Postgres store answers the same refusals with
the same codes, and the in-memory store answers an oversized new value
with
secret-value-too-large.
- Under
kindgi devsays what stopped it: when something around it refuses what it needs,kindgi devsays what was refused and what to do, and so dokindgi doctorandkindgi auth registryfor Docker.- A
dockerthat can't be started (spawn docker EPERM), a Docker socket that refuses the connection, and an engine that doesn't answer each get their own message.kindgi devno longer tries to pull the runtime image when it can't reach Docker, and no longer suggests installing Docker, or another Postgres, when Docker is there. - When it isn't allowed to listen on any port of
127.0.0.1(listen EPERM), it says so, where it read every port as in use. A pack service that can't listen gets the same. - A file or folder it can't write (
EROFS,EACCES,EPERM) is named, with the code. - Each of these ends with what a coding agent's sandbox needs: "If a
coding agent runs this, its sandbox is likely what stops it: run
kindgi devin your own terminal instead." - A
docker logsthat can't start while the runtime starts no longer stopskindgi dev.
- A
- Build logs: a build's log stream that's cut before its end is opened again, and the lines it replays are printed once.
- MCP servers: an MCP server whose
outputSchemadoesn't compile no longer fails its tool listing: its tools are listed, and that tool's results fail with "The server's outputSchema doesn't compile: …" (MCP servers). - Proposals: evaluating a proposal whose model settings aren't valid
model settings is refused with
400 validation-failed, and nothing is stored. - Logs: a
501answer is logged atinfo, noterror: the runtime doesn't offer what was asked, and nothing failed. So underkindgi dev, the console's permissions read no longer prints anERRORline. Every other answer of 500 or more stays aterror(Logs). - The license key: the license renewer's key (
kgi_lrk_…) is masked in logs, like every other Kindgi token. - Listing secrets:
kindgi secrets list --include-revoked, andincludeRevokedin the clients (include_revokedin Python, which gains it), now list revoked secrets too, with theirrevokedAtandrevokeReason, never a value. Before, the API dropped the flag.- The list comes in pages, by name: 25 to a page,
--limitup to 100, and while more remain anextCursorto pass as--cursor. Thekindgi devstore used to stop at the first page, so a 26th secret was out of reach. Acursorthe list didn't issue is400 bad-input. - Names come in byte order, whatever the store or the database's
collation: capital letters before lowercase ones, and
-and.before letters (ORDERS,orders-db,orders.db,ordersa). A runtime on Postgres used to follow the database's own collation. - A secret's versions,
GET /v1/secrets/:name/versions, come in pages the same way, oldest first. - A runtime before 0.1.8 returns only the first page of either list,
with no
nextCursor, and ignores--include-revoked(Store a secret).
- Routing names a model provider the runtime can't set up: a provider
registered for the tenant whose settings the deployment no longer allows
used to leave only
422 capability-routing-failed, "No registered provider satisfies the capability declaration", with the reason in the runtime's log alone. Now the message names the first such provider and the setting its adapter refuses (or, when the adapter fails to build it, says the runtime's log has why), and counts the rest; the reasons list each underprovider set upwith the codeprovider-setup-failed, andGET /v1/providers/{providerId}/checkgives the adapter's own words (Choose a model). - A tenant SSO sign-in whose identity provider's userinfo request fails
(the provider can't be reached, or
KINDGI_TENANT_HOST_ACCESSrefuses its address) now ends at the sign-in page withsign-in-unavailable, and the runtime logs why undersso. It ended at an empty 500 page. No session is created.
Changed
Section titled “Changed”- A runtime release stops starting 90 days after it's released: from
0.1.8 until Kindgi 1.0, in every mode, unless a production key exempts
it. Releases before 0.1.8 don't expire. A running server keeps running,
but a platform that restarts instances on its own (Cloud Run, Container
Apps) doesn't bring one back after that day. The startup banner, the
console and
kindgi devwarn from 30 days before, andGET /v1/licensereports it aspreview(Preview releases stop starting after 90 days). - MCP endpoints with a credential in
config.headers: registering an MCP endpoint with a header whose name says it carries a credential (Authorization,X-Api-Key, …) inconfig.headersis refused:invalid-mcp-endpoint, reasoncredential-in-headers. Send it by reference instead, withauth: { scheme: "header", headers: [...] }(MCP servers). An endpoint registered that way before 0.1.8 keeps working. It reads back[redacted]for each such header, its requests never follow a redirect, andkindgi doctorwarns about it. - Gemini through a proxy: the Gemini adapter calls Google's own host
for the Developer API and for each Vertex AI location.
GOOGLE_GEMINI_BASE_URLandGOOGLE_VERTEX_BASE_URLin the runtime's environment no longer move its calls. If you set either to send Gemini calls through a proxy, they now go to Google directly. - What Kindgi reads from the servers it calls:
- An HTTP tool's
timeoutMs, and a run's cancel, now cover reading the answer, and an answer over 10 MiB fails the call (HTTP tools). - Kindgi asks the servers it calls for you (MCP servers, HTTP tools, a
model's base URL, your identity provider, an image registry) for
answers sent uncompressed (
accept-encoding: identity). An answer sent compressed anyway is refused, never decoded. - An answer is read up to 10 MiB. An event stream (an MCP server's) is bounded per event, so a long stream keeps going.
- Your identity provider and an image registry have 120 s to start answering.
- Verifying an image reads its manifest up to 4 MiB and the file it needs
up to 10 MiB, and cuts a layer that sends more than its manifest
declares. The deploy answers
400 image-unverifiable, its message naming the limit. - A layer that isn't a readable tar archive is refused, naming the
archive's error:
Layer … isn't a readable tar archive: TAR_ENTRY_INVALID: checksum failure, or…: TAR_BAD_ARCHIVE: Truncated input …for a file cut short, which was read cut short before. - A pack service's refusal is quoted up to its first 4 KiB, ending in
…when there was more.
- An HTTP tool's
- Request size and depth:
- A request body over 10 MiB is refused with
413 request-too-large, whosedetails.maxBytesis the limit. JSON that nests objects and arrays more than 128 levels deep is refused with400 bad-input, whosedetails.maxDepthis the limit. Both were accepted before. An artifact upload keeps its own size limit (413 artifact-too-large), and its body isn't read as JSON; the webhook receiver keeps its own too (413 webhook-body-too-large). - A signed webhook delivery whose JSON event nests more than 128 levels
deep is refused the same way, and starts no run. The trigger's fires
record it with
detail: body-too-deep(Start runs from webhooks).
- A request body over 10 MiB is refused with
- Schemas: a JSON schema over 1 MiB as JSON, or nested deeper than 64 levels, is refused when it's published, and nothing is stored. One stored before 0.1.8 is refused the first time it's used. That's every schema you write: a tool's input and output schemas (an MCP server's tools too, when it lists them), an agent's typed output, a flow node's output, a settings block's schema and a guardrail's config schema.
- Guardrails: a built-in check's regular expression (
must-cite'ssourcePattern,output-matches'pattern) longer than 8,192 characters with its flags is refused like one that doesn't compile: registering the guardrail answers422 guardrail-config-invalid, and deploying a pack with one fails withdeployment-validation-failed. A guardrail registered before 0.1.8 with one can't run its check (Use a built-in check). - Prompt templates:
- Template renders on a self-hosted server and under
kindgi devnow have a memory limit: 16,777,216, in the template engine's memory units, roughly the characters of the strings the render builds and the items of its arrays. No setting changes it. A render past it fails the agent's turn withmodel-invocation-failed:Prompt render failed: Template render failed: the render went over its memory limit of 16777216. - An agent's instructions are checked as Liquid when the agent is defined,
published (
POST /v1/agents) or deployed. Instructions that aren't valid Liquid, or that use an unknown filter, are refused there; before, they were accepted and failed at every render. A deployment with such an agent is refused whole. To write{{or{%as text, put it in{% raw %}…{% endraw %}. - A prompt block whose template uses an unknown filter is refused when it's published. Rendering it always failed.
- Partials (
{% include %},{% render %},{% layout %}) are refused wherever a template comes in, with "templates can't use include, render or layout". A template stored with one before 0.1.8 fails when it's rendered (render-failure), with the same message; nothing stored is changed.
- Template renders on a self-hosted server and under
- What a project reaches:
- A run that names a project runs only an agent or flow that project
reaches. Naming one it doesn't is refused with
400 reference-out-of-scope:This project can't reference agent "<id>": it isn't registered in this project, its org or the tenant. - Registering an agent, flow or guardrail is refused the same way when it names a tool, agent, flow, guardrail or data block its project doesn't reach, or one that doesn't exist yet: register a guardrail before the agent that names it.
- A guardrail names a pack check only when a guardrail of the same project names it already: a deployment brings its checks with its guardrails. Built-in checks work in every project.
- Under
kindgi dev, the echo provider'sdemo.echotool is every project's, and the seededdemo.echo-agentis the Default project's: another project needs agents of its own. - A conversation opened before 0.1.8 in a project its agent isn't
registered for can't be continued:
404 agent-not-found,The conversation was opened with agent "<id>@<v>", which is no longer registered.The runtime names such conversations when it starts. - An MCP endpoint's catalog tools are reached by the endpoint's scope.
- A tool id is served as an MCP catalog tool only while every version of
it that counts is one the catalog sync wrote. A version published under
the same id (an HTTP tool, say) turns it off in every project until
that version is unregistered; an unregistered version still counts
while a flow or agent version pins it. The runtime logs
mcp-tool-unroutablefor such a tool:MCP tool <id>@<v> isn't served: <id> also has a version the MCP catalog sync didn't write (<versions>), so no version of it is a catalog tool. Unregister it; one a flow or agent version still pins counts until those versions are replaced.Retiring an endpoint unregisters only the versions the sync wrote. - A tool's metadata can't set
kindgi.keys:POST /v1/toolsand deploys refuse it.
- A run that names a project runs only an agent or flow that project
reaches. Naming one it doesn't is refused with
- Secrets:
- A tool version, MCP endpoint or webhook trigger registered on 0.1.8 records where each secret it names is read. A name its record lacks is read nowhere, never at the tenant. Only an item registered before 0.1.8, with no record at all, reads at the tenant as before.
- A webhook trigger registered on 0.1.8 reads a signing secret set for its project or its org. On 0.1.7 such a secret wasn't read, and every delivery was refused (Register the trigger).
- A tool version whose publisher administers no scope an optional secret
could be read at fails every call with
secret-unavailable, as it does for a required one:tool "<id>" reads no secret "<NAME>": whoever published this version administers no scope it could be read at. A project admin publishes a new version.The call is refused before any of its secrets is read. An optional secret that simply isn't set still lets the call go on without it. - Unregistering a version stops it being chosen, not the pins that hold
it: a flow version runs the agent version each agent step holds and the
tool versions it pins, and an agent version runs the tool versions it
pins. The check and the startup warning also list an unregistered tool
version a flow or agent version still pins, marked
(unregistered, still pinned). Its fix: publish a new tool version; for an agent that pins it, publish an agent version whose range takes the new one and make it live (kindgi agents promote); then publish a new version of each flow that pins the old tool or runs the old agent version, changing an agent step that names that version. The order matters: a flow pins each agent at its live version when the flow is published, so a flow published before the new agent version is live pins the old one again. The startup scan also warns about an unregistered agent version a flow version still runs.
- Conversations and memory:
- Running a turn as an end user (
participantId) takes being that person, orwriteon the project, as reading their memory does; anyone else gets403 participant-not-allowed. Nothing changes for existing callers: every role that can run an agent holdswrite. - With authorization on, an agent whose
memory.remember.scopeis'tenant'proposes a fact for the whole tenant only in a turn whose caller, a person or a key, is a tenant admin: facts every project reads are a tenant-level decision. With anyone else the call doesn't run, and the model is told it needs a tenant admin. The other scopes are unchanged (Give an agent memory).
- Running a turn as an end user (
- Webhooks: IPv6 site-local addresses (
fec0::/10, deprecated since 2004) count as private. Outside development mode they're refused, as other private-network addresses are, unlessKINDGI_WEBHOOK_PRIVATE_NETWORKS=allow, which opens them too. - Suspending a tenant or a project (a runtime serving many tenants):
- A suspended tenant's or project's webhook deliveries are answered
202withskipped: tenant-suspendedorskipped: project-suspended, as a paused trigger's are, so a sender such as WooCommerce doesn't count them as failures. The event isn't kept: a sender that can resend by hand can send it again once the tenant or project is restored. - A closing tenant refuses webhook deliveries with
409 tenant-closing. When the tenant's state can't be read, a delivery gets503 tenant-state-unavailablewithRetry-After. - A schedule's or a webhook trigger's fire that a suspension stops, or
whose run starts as its tenant is suspended or starts closing, is
recorded
skipped, with the reason in itsdetail. It doesn't count toward a schedule's auto-pause. A tenant's suspension isn't caught up after the restore, whatever the schedule'scatchUp. - Suspending a tenant or a project that's already suspended keeps the first suspension's time and reason.
- A suspended tenant's or project's webhook deliveries are answered
- The CLI:
- A deployment larger than the server takes in one request now says what to do: "The deployment is larger than the server takes in one request. Every tool, agent, flow and guardrail in the pack travels in it with its schemas and instructions: make the largest schemas smaller, or split the pack into two."
kindgi dev's banner has aModelsline in place ofProviders: each provider with its models or, with none yet, what agents do meanwhile and a link to Models.kindgi init's next steps say the same.kindgi doctorstill names thekindgi providers registercommand to run.- A build service's refusals print plainly, with their code and the wait
they ask for. A
429withRetry-Afteris waited out, and the same build is sent again. kindgi deploy --projectchecks the project before an inline build, so a project that isn't there fails before anything is built.- Your API key goes only to the address it's for.
kindgi deploywith a stored key (the onekindgi auth loginkeeps, orkindgi dev's.kindgirc.json) refuses to send it to another address, wherever that address is named:--endpoint, an environment'sendpoint,--url,KINDGI_API_URLor a folder's.kindgirc.json. The refusal names both addresses and how to fix it. A stored key with no address stored beside it is refused too. A key given with--tokenorKINDGI_API_TOKENgoes where the command says, as before. Addresses are compared after normalizing: a host's case, a scheme's default port and a trailing/don't count, andlocalhost,127.0.0.1and[::1]are one address. - With
--hosted, orbuild: 'hosted', the build and the deploy go to the CLI's own API address (--url,KINDGI_API_URL, or the one you signed in to), and an environment'sendpointmay only repeat it. Before, an environment'sendpointwon. They don't read a.kindgirc.jsonthat's for akindgi devruntime: onekindgi devwrote (with--runtime-urltoo), or one atlocalhost,127.0.0.1or[::1]. - A build that signs checks its key before building anything. With no key, it stops and says how to make one, have it trusted and name it. A key file that isn't there, or isn't a file, stops it too, naming the path and where it was set.
kindgi init's TypeScript templates leaveenvironmentsempty, with a commented Kindgi Cloud block and a commented block for a runtime of your own. Before, a new pack carried placeholder environments that a deploy would use.kindgi deploy --project <slug>with no such project points tokindgi projects list. It named a command that doesn't exist.kindgi adapters prepare --paramsreads its JSON from a file with@<file>, as its usage line said and as every other such flag does. JSON that doesn't parse is a usage error (exit2), and nothing is sent.- Four commands' help now says what they do.
kindgi dev --tenant: with the bundled Postgres, the default tenant is the project's own, the same for every pack and restart; otherwise it's the last run's, from.kindgirc.json, else a new one.kindgi build --signer-key-id: the default is the environment'ssignerKeyId, else the key file's name.kindgi sso providers start:--kindis optional, and comes from--idp, else from the registered provider.kindgi schedules update: a flag left out keeps the schedule's value. kindgi artifacts upload --help, the API's description ofPOST /v1/artifactsand the clients' docs give the default upload cap as 100 MiB, what it always was (100 * 1024 * 1024bytes). They said 100 MB.
- The license key's signing key: the runtime and the CLI trust a new production signing key, so a production key issued after 0.1.8 can need runtime 0.1.8 or later. Kindgi tells you which runtime a key needs when it issues it, and a licensee on an older runtime keeps getting keys their runtime verifies.
- Logs:
KINDGI_LOG_LEVELSnow warns at boot forauthanddb: nothing logs under them, so a level set for either never had an effect. Levels forjudging,migrations,ssoandtenantsalways applied, and no longer warn that they don't.- Records from
aws-identityandopenfganow carry their own subsystem, where they saidroot, so a level for either applies too. - The scheduler's lines are now records under
schedules: each fire, with its outcome and the run or improvement pass it started; a trigger paused; what a restore skipped; and failures. So are theimprovement-passeswarning that passes couldn't resume, and theauthz.outboxwarnings a request printed while it waited for its access changes to apply. They followKINDGI_LOG_LEVELSandKINDGI_LOG_FORMAT: under JSON each is one object on its own line, where it used to break the stream (The subsystems).
Known issues
Section titled “Known issues”- A first admin who stops being a tenant admin loses their capabilities, and being made one again doesn't return them. Keys that carry them make new keys with them, so replace the last one before it goes. With neither, contact support (Make someone a tenant admin).
- Run one runtime instance. Several instances sharing a database aren't verified on a platform yet, so the Cloud Run module still runs one (Cloud Run).
- A secret hard-revoked before 0.1.8 in your own secret manager
(
KINDGI_SECRETS_BACKEND=secret-manager) lists underkindgi secrets list --include-revokedas a revoked secret: its name,revokedAtandrevokeReason, never a value. The runtime kept nothing then that told a hard revoke from a soft one. A secret hard-revoked from 0.1.8 on is left out of every list. - With a key for OpenFGA (
KINDGI_OPENFGA_PRESHARED_KEY),kindgi-runtime tenants purgeandtenants repurgestop at a tenant with an OpenFGA store: they don't send the key, or the ID token behind Cloud Run IAM, so the store's delete is refused, and they exit2withOpenFGA answered <status> to deleting store <id>. By then the tenant's artifacts' bytes are deleted, but none of its rows. A repurge stops there, before the records after it. Fixed in 0.1.8.1, the next release: once you've upgraded to it, run the purge again (Close and purge a tenant).
Upgrade steps
Section titled “Upgrade steps”- Before you upgrade, list the MCP endpoints with a credential in
config.headers, with the 0.1.8 image'scheck mcp-header-credentials(Operate). They keep working, but move each one: store each header's value as a secret, then unregister the endpoint and register it again with the header inauth(MCP servers). - Before you upgrade, list what reads a secret at the tenant from a
project or an org, with the 0.1.8 image's
check secret-scopes(Operate). They were registered before 0.1.8 and keep reading at the tenant. One a tenant admin registered can stay. The check ends with what to do about the others: register each again, a webhook trigger withkindgi webhooks update <trigger-id> --secret=<name>. - If a server Kindgi calls compresses its answers whatever the request asks, turn that off before you upgrade: 0.1.8 refuses a compressed answer.
- Check that your agents' instructions are valid Liquid. A deployment with an agent whose instructions aren't is refused whole, so a CI deploy that passed on 0.1.7 can fail on 0.1.8.
- Expect a slower first start on a large database. Two new indexes on the runs table are built at the first start after the upgrade, without blocking writes; the more runs, the longer that start takes.
- After you upgrade, read the startup log for conversations that can't be continued (opened before 0.1.8 in a project their agent isn't registered for) and for unregistered versions a flow or agent version still pins: the runtime names each.
- If a deploy sends the key
kindgi auth loginorkindgi devstored to another address, give it that server's key with--tokenorKINDGI_API_TOKEN, point the address at the one stored with the key, or, for a key fromkindgi auth login, sign in to that server withkindgi auth login --url <url>. The 0.1.8 CLI refuses to send a stored key anywhere else, and the refusal names the setting that names the other address.