Kindgi 0.4.0
Released November 3, 2026. For the docs of this version, see docs.kindgi.com/v0.4.0.
Security fixes
Section titled “Security fixes”- An erasure now reaches a test run's stored results, and a test run
still going. Before, erasing a person's words cleared a test run's case
results as it ran, but not the copy in the finished run's result
(
perCase), which reads serve once it ends. Now both copies are cleared. A test run still going with a case of that person's is waited for, and the erasure showswaiting-on-run, withwaitingOnnaming it, then cancels it at the deadline:KINDGI_ERASURE_SHARED_WAIT_MS, 7 days by default, or sooner when a tenant admin forces it (kindgi memory erasures resume <erasure-id> --force). A failed model call in Improve's drafter now records "The drafter's model call failed." in place of the provider's message, which could quote corrections and which an erasure couldn't reach.
-
Files in an S3 bucket.
KINDGI_ARTIFACTS,KINDGI_ERASURE_LEDGER_EXPORT,KINDGI_TENANT_PURGE_RECORD, and thetenantsanderasurescommands'--record,--from,--ledgerand--out, takes3:<bucket>[/<prefix>], on AWS S3 or a store that speaks S3, such as MinIO or R2.KINDGI_S3_REGIONnames the buckets' region. On AWS the runtime signs in as its AWS identity (KINDGI_AWS_IDENTITY); a compatible store takesKINDGI_S3_ENDPOINT,KINDGI_S3_PATH_STYLEand its own key inKINDGI_S3_CREDENTIALS_PATH. A delete removes every version of a file and its unfinished uploads. The runtime checks aKINDGI_ARTIFACTSbucket ons3:at start, and refuses one with MFA Delete on, or an Object Lock default retention, since a tenant purge couldn't delete from it, and one it can't list unfinished uploads in (s3:ListBucketMultipartUploads), or versions in, when it keeps them (s3:ListBucketVersions). The erasure ledger and purge records need a store that honorsIf-None-Match(Choose where the runtime keeps files). -
The Azure Container Apps module has an
upgrade.sh. A deployment of the module on runtime 0.1.8 or later, in either network shape, can run it to upgrade to 0.2.0 or later, as the Cloud Run module's does. It copies the new image into the module's registry, runs the upgrade checks against the database as Container Apps jobs in the module's environment, checks that the database server keeps at least 7 days of backups, and changes the running deployment only when you typeyesat a plan it has checked. If the new revision doesn't come up, it prints the way back, which restores the database server as of just before the apply, into a new server, rather than rolling back on its own.--dry-runlists what a real run would change. Use it as of the@kindgi/sdk@0.4.0tag. The module's newdatabase_url_versionpins the version of thedatabase-urlsecret the server reads: the way back sets it, andupgrade.shrefuses to start while it's set (Azure Container Apps). -
Retired blocks, policies and release gates can be found.
GET /v1/blocks,/v1/policiesand/v1/release-gatestake?includeRetired=true, as the lists of agents, flows, tools and test sets do: one whose every version is unregistered is listed as its highest version, withunregisteredAt, so you can reinstate a version. In the TypeScript client,blocks.list,policies.listandreleaseGates.listtakeincludeRetired, and in the Python clientinclude_retired. In the CLI,kindgi blocks listandkindgi release-gates listtake--include-retired.kindgi exports createnow includes them too (Agent and tool versions). -
On Cloud Run, each deployment gets a pack service of its own. The module runs the pack orchestrator, a Cloud Run Job that Cloud Scheduler starts once a minute: each pass makes a service for each deployment that needs one, gives running ones their changed env, and retires what should go. A service scales to zero when it's idle, and its first call after that waits for an instance to start. The pack's env comes from Kindgi, with
kindgi env set, and a secret of yours in Secret Manager can be one of its values, as a cloud secret pinned to a version (Run a pack service for each deployment on Cloud Run). -
Correcting an agent, its test set, and Improve work as one loop.
- A correction says what was wrong and who fixes it: Improve, a developer, or the agent's owner, which each agent now has. Its status is Open, Being fixed, With the owner, Fixed, Won't fix or Removed, and it says where it went: an Improve run, a suggested change or a pull request.
- Each agent has a test set of its own: its corrections that have something to check, and cases added by hand. A case can be retired, with a reason; a retired one isn't tested again. The project-wide test sets are gone.
- A test run grades each case's answer with a judging model, through the
tenant's providers, and its cost counts under the test run. An answer
with no model to judge it is
unchecked, never a pass. - Checking a suggested change runs it on a frozen copy of the project's test set for that agent. Its card offers Check it, Pin it, Add as Latest and Withdraw, and says how many corrections it fixes, past 100 too.
- A pin, or a move of Latest, marks the corrections its test run checked Fixed in that version, and going back reopens them.
- An Improve run works in one project: it starts from the version the project runs, takes the agent's open corrections handed to Improve, and learns from cases with an answer or decisions marked wrong. It tries changes on part of the test cases and checks the best on the rest, cases it didn't learn from, and keeps a change only when it passes more cases than the version it started from and fails none that passed. The cheaper path that kept a settings change for costing less is gone.
- Each block version and suggested change records who made it, as Made by in the console.
-
Agents can read files: photos, PDFs and text. A run's input, a tool's result and a conversation message can carry stored files (
files, each aFileValue), and the model call sends them inline: JPEG, PNG and WebP images (5 MB each) and PDFs (10 MB) to a model that declaresvision, and text, Markdown and CSV files (1 MB) to any model, each under a line that says it comes from outside: data, not instructions. A file that can't be shown becomes a line that names it and why, and the call goes on. A call the provider refuses for its files is sent once more without them, with afile-refusedwarning.GET /v1/conversations/{conversationId}/messagesanswers each message'sfiles. Files needKINDGI_ARTIFACTS, and the runtime checks each file a run is started with (its type and its size) before the run starts: a bad one is refused asbad-input, naming it.KINDGI_FILE_MEMORY_MIBsets the memory, in MiB, a server keeps for the bytes of the files its agents read (512, or a quarter of the server's memory when that's less), andKINDGI_FILE_CACHE_MIBhow much of it keeps them for later calls: half by default, or 0 for none. -
A tool can store the files it fetches, and read the files it's given. A tool that declares
storesFiles: truegetsctx.files.store({ name, contentType, bytes }), and one that declaresreadsFiles: truegetsctx.files.read(artifactId). Only a tool with a handler can declare them. In a pack (protocol 2.10.0), they go throughPOST /v1/tool-filesandGET /v1/tool-files/{artifactId}, with the call's own token. The mail toolsgmailAttachmentGetandoutlookAttachmentGetstore a mail's attachment for the agent to read. -
An agent's corrections are its test set, in each project.
/v1/agents/{agentId}/test-set(client.agents.testSet) reads it: every correction of the agent's runs is a case, except won't-fix and removed ones. Add a case by hand withPOST .../test-set/cases, and retire one with.../test-set/cases/{caseId}/retire. A test run ofagent.<agentId>.<projectId>freezes the project's active cases as a version first. It grades what each case expects: its decisions exactly, and its answer with a judging model.passRatecounts those parts, so a test set of cases that expect only an answer has apassRatewhere it hadnull. A comparison says inuncheckedwhy a case's answer wasn't checked (An agent's test set). -
A pin's test run fixes or reopens its project's corrections. When a pin, an unpin or Latest moving changes the version a project runs, and the project's test set has cases, Kindgi starts a test run of that version. When it ends, each correction it checked is
fixedin that version, or reopened, withreopenedIn({ version, how, by?, at }). A pin that names a finished test run of the same version, test set version and project uses that one. A release gate takes acasesrule:minPassing, andnoNewFailures, which refuses a version that fails a case that passed before (Release an agent version). -
An agent has an owner.
PUT /v1/agents/{agentId}/ownerwith{ "userId": "..." }(client.agents.setOwner), with admin on the agent, names the person who owns it, andGET /v1/agents/{agentId}answersowner: { userId, name }. A correction's wrong decisions go to the owner.kindgi agents owner <agent-id>shows it, and--set=<user-id>sets it. -
Corrections export, and come from your users' thumbs.
GET /v1/corrections/export?agentId=<agent-id>streams an agent's corrections as CSV, or as JSON lines withformat=jsonl, and the audit log records each export.client.corrections.exportandkindgi corrections export --agent=<agent-id>give it, and--out=<file>writes it to a file.client.corrections.thumbsrecords an end user's thumbs up or down from your app's server, as a correction of the run's answer; a thumbs down needswhy. A suggested change says how many corrections it fixes incorrectionCount(Record your users' thumbs). -
A reviewer can approve a fact with their own text.
POST /v1/approvals/{approvalId}/completetakesfactText, withdecision: approveon afactapproval only (any other answers400 bad-input), and the fact holds that text in place of the agent's. It's checked as the agent's own text is: not empty or only spaces, and at most 2,000 characters. The decision carries it asdecision.factText, andapprovals.decidetakes it. Theremembertool no longer stores a text of only spaces. -
A block version says who published it, where it came from, and where it runs. A block version has
publishedBy, andsource:api,deploywith the deployment's id, orsuggested-change.GET /v1/blocks/{blockId}/runs-in(client.blocks.runsIn) lists each project, and each segment pin, whose running agent version uses a version of the block, and whether the pack's files have it (inYourFiles).kindgi blocks pullwrites the newest running version of each block into the pack's block files, and never over a file that's newer. Publishing, unregistering and reinstating a block version, and registering and unregistering a provider, are in the audit log. -
A deployment records where its pack lives in git, and a project can open pull requests.
kindgi deploy, in a git work tree, sendssource: theoriginremote ashost/owner/name, the pack's folder, the commit, the branch, and whether the folder had changes the commit doesn't hold.PUT /v1/projects/{projectId}/repo-connection(client.projects.setRepoConnection) sets the company-wide GitHub connection a project opens its block changes' pull requests through. That connection's GitHub App needs Contents and Pull requests, read and write. -
A block change opens a draft pull request in the project's repo. When a block version is pinned in a project, or added as its Latest, Kindgi opens a draft pull request with the new block files, through the project's repo connection: a company GitHub connection, for github.com, that a project admin picks on the project's Connections page, under Pull requests for block changes. Its first paragraph says where the change came from ("From an Improve run.", or "From a scheduled Improve run."), how many corrections it fixes, and its test set score, such as "Test set: 25 of 27, up from 23.". One that can't be opened is logged, not retried;
kindgi blocks pullbrings the version into your files instead. None is opened underkindgi dev. A block's versions show where each runs, and whether your files hold it. -
A suggested change is pinned, or added as Latest, for its project.
POST /v1/suggested-changes/{suggestedChangeId}/pinpins its version through the project's release gate..../add-as-latest(client.suggestedChanges.addAsLatest,kindgi suggested-changes add-as-latest) makes it the Latest of a project on Latest, with no gate. One built on a version its project no longer runs is built again on the version it runs now, with a new check: pinning it, or adding it as Latest, first answers409 suggested-change-out-of-dateand starts that (details.rebuilding). One the project's version already has, or whose block that version no longer uses, isn't built again (rebuilding: false). A deploy makes a suggested change in each project that pins another version of the agent (madeBy: deploy). It's never built again: once its project moves, pinning it answers the same 409 withrebuilding: false. Making, pinning, adding as Latest and withdrawing one are audit events. -
kindgi suggested-changes pull <suggested-change-id>writes a suggested change into the pack's files. With--pr, it commits them on a new branch and opens a pull request (withgh), and marks the corrections it fixes that are stillopenasbeing-fixed. Bothpullcommands refuse a block file that holds edits the runtime doesn't have, naming it, and write nothing (Suggest a change, and test it). -
kindgi flowsandkindgi toolspin versions. Each haspinned,pinned-versions,pin,unpinandpin-history list, askindgi agentshas, per project, org or tenant (Pin a flow's version). -
Under
kindgi dev, Improve runs, and a pin keeps what it writes over in your pack's files. A pin for the whole workspace writes the version into your pack's files, as making a version live did before. It now keeps what it writes over, so pinning the version before undoes it, where before the way back was git, and an edit made since the check is no longer written over: the pin answers409 pin-superseded, which waspromotion-superseded. An unpin is still refused. Before a pin writes,kindgi agents pinandkindgi suggested-changes pinsay which files git hasn't committed (uncommittedFilesandnotInGiton the pin check), as the console's pin dialog does, and the pin still goes.POST /v1/improve-runs, Suggest a change and Check again work there, and an Improve run's suggested change is for the whole workspace. Improve schedules are off there: start Improve by hand. Thereturns-helpertemplate's README walks the loop end to end. -
Calendar tools.
@kindgi/connections/google/toolshasgoogleCalendarEventsList,googleCalendarFreeBusy,googleCalendarEventCreateandgoogleCalendarEventUpdate, and@kindgi/connections/microsoft/toolshas the fouroutlookCalendar*tools. Create and update invite people, so they wait for a yes in a run no person started. A connection made for mail only needs the calendar permissions added (Calendars). -
A WooCommerce store connects with its owner's approval. In a pack made with
kindgi init --template=woocommerce,pnpm connect-store https://shop.example.comopens the store's WordPress Authorize Application page (WordPress 7.0 or later). Once one of its administrators approves, it makes thekindgi-agentuser a Shop Manager and savesWOO_STORE_URL,WOO_USERandWOO_APP_PASSWORDin the pack's env, with no password copied by hand.--hosted --env=<env> --scope=project:<id>saves them for a deployed pack. -
kindgi init --template=returns-helper, and skills that teach the correcting loop. The template is one agent with a find-order and a refund tool on sample orders, and three blocks. Thekindgi-fix-correctionsskill reads the open corrections sorted to a developer and fixes each where it belongs. The authoring skills say how an agent takes its instructions and settings from blocks, and what a tool call's deadline does: the pack service aborts the handler's signal atKINDGI_PACK_CALL_TIMEOUT_MS. -
The pack orchestrator's routes and settings.
kindgi-runtime packs orchestrateruns one pass of the pack orchestrator and exits, for a Cloud Run Job once a minute, with a system key that hassystem:deploymentsandsystem:pack-env. It readsKINDGI_ORCHESTRATOR_RUNTIME_URL,KINDGI_ORCHESTRATOR_SYSTEM_KEY,KINDGI_ORCHESTRATOR_PROJECT,KINDGI_ORCHESTRATOR_REGION,KINDGI_ORCHESTRATOR_PACK_SERVICE_ACCOUNTandKINDGI_ORCHESTRATOR_PACK_SERVICE, and gives each pack serviceKINDGI_PACK_SERVICE_MAX_CONCURRENCY, its concurrency. For a runtime behind Cloud Run IAM,KINDGI_ORCHESTRATOR_RUNTIME_AUTH=google-id-tokenadds a Google ID token to its calls. Each pass claims the round (POST /v1/system/deployments/round), and a deployment still waiting for its pack service carries its lastproblem. A new code,pack-env-name-too-long, there or on a ready one'spackEnvProblem, means a name set as a secret is too long for the secret it's kept in, which is named after the pack service. The logs name the subsystemspack-orchestratorandblock-version-prs(Run a pack service for each deployment on Cloud Run). -
Per-deployment pack routing works on a runtime that serves one tenant, and can seal under a key of yours.
KINDGI_PACK_ROUTING=per-deploymentneededKINDGI_TENANCY=multiandKINDGI_SECRETS_BACKEND=postgres. A one-tenant runtime now takes it too, withKINDGI_PACK_ENDPOINT_HOSTSnaming the hosts a deployment's endpoint may be on, and each endpoint's token can be sealed underKINDGI_PACK_ENDPOINT_KMS_KEY, a Cloud KMS key or a Key Vault key, in place of the secrets' own. -
Only the operator sets a pack's env name to a cloud secret. With
KINDGI_ENV_CLOUD_SECRETS=on(it needsKINDGI_PACK_ROUTING=per-deployment; off, the default, its routes answer501 cloud-secrets-unsupported), a system key withsystem:env-refssets a name toprojects/<project>/secrets/<secret>/versions/<number>, askindgi env set NAME --cloud-secret <path> --tenant=<id>does. A tenant's own key is refused (403 cloud-secret-system-only). The tenant sees the names, never the path:GET /v1/env/cloud-secrets, andkindgi env listprintsNAME (cloud secret). -
kindgi deploy --hostedsays how many builds are kept, andkindgi deployments getwhat keeps each. A build's pack service stays while something a call can still ask for needs it, and no newer deployment into its project serves that.kindgi deployprintsBuilds kept in this project: N(workspace, when the deploy names no project), andkindgi deployments getlists what keeps the build underKept for:(endpoint.keptFor, andkeptBuildsonGET /v1/deployments).kindgi deploymentssays why asupersededone was taken down (Deploy your agent to Kindgi Cloud). -
Every union in
openapi.jsonmaps its tags. Nine unions, among themAgentPinScope,PinScope,ImproveRunOutcomeandMCPEndpointAuth, now have adiscriminator.mapping, so a client generated from it types each tag as the value the server sends, such assuggested. Nothing on the wire changes. -
In the console:
- On a runtime that serves many tenants, the runtime card says Kindgi Core is run for you, with nothing to set up or upgrade.
- An empty list says what goes in it, and how to add one.
- The project's Approvals card also counts approvals that belong to no project.
- An agent's corrections can be exported, as CSV or JSON lines, and each export is recorded in the audit log.
- An agent's tools list the version each tool's runs call.
- A reviewer can approve a fact an agent wants to remember in their own words.
- A run's corrections form says what to judge, and who fixes it.
- Corrections, and each Cost report, have a page for each of what were their tabs: To review, To fix, Who corrects, Rules and Trends, and By agent and the like. The trail's last crumb lists them, and their addresses are the same.
- Correcting links each next step. A saved correction links To fix while it isn't fixed, Run Improve on its agent when it's Improve that fixes it (for whoever may run Improve), and its case in the test set. Next run to review opens the next run's Corrections page, and a run's header has Correct this run.
- An agent's and a flow's Corrections page is the project's To fix list for that agent or flow, with its filters in the page's link. A test set's case opens its run's Corrections page, an Improve run links the test set it ran on, and a pinned version links the suggested change it came from. Correction lists name each run, which opens its Corrections page, and a rule's open count opens To review for that rule. Saving over a correction on its way to a fix says which one it replaced.
- A pin that would take a project off Latest warns first: pin and stop following Latest, or cancel. On a suggested change, you can add it as Latest instead.
- An agent's Projects section shows the version each project runs, whether it's pinned or follows Latest, and when a pin took it off Latest or an unpin put it back. Its highest version links to the suggested change waiting in each pinned project.
- An Improve start that isn't ready says how to fix each thing it's missing, and one refused while another run is going links to that run. An Improve run's page shows the check of its change on every case of the test set, against the version as it is.
- Approvals come in two groups, Tool calls and turns, then Versions to pin, and the Inbox names each approval's group and filters by it. An approval with no project says why: it's for the whole workspace or an org, or it's from before Kindgi 0.1.3.
- The new suggested change form keeps Suggest it off, and says so, until the content differs from what the version pins.
- On the tool, flow, block and agent pages, a version's link keeps the versions table's Show retired, sort and page.
-
The WordPress plugin 0.2.0 has a Kindgi menu. Inbox, Activity, Ask and Settings are pages of their own, in the person's admin color scheme. The Inbox lists what waits for you, what waits for someone else and why, and the project's decided approvals. A card reads in words, and its buttons say what each decision does, such as Approve and send on a reply. A count of what waits for you shows on the menu and in the admin bar. Activity is a feed of the project's runs by day. Ask reads as a chat, and a call that didn't go through says why: it wasn't allowed, a guardrail or a connection stopped it, a reviewer rejected it, or it failed. Settings, once the site is connected, opens on a status card. The WordPress dashboard has a Kindgi box, and on a WooCommerce store an order's screen has one too, with a Kindgi column on the Orders list. Upload
kindgi-0.2.0.zipfrom the 0.4.0 release over the plugin you have (Let a store's staff ask and approve in WordPress). -
A site person's Ask can use the site project's tools, behind an approval floor. A person the site signs in, whose role may ask, now has the project's tools in their own agent turns. There, every call of a tool that isn't declared read-only (
mutating: false) in every one of its versions waits for a yes, and so does everykindgi_remember. An MCP tool always counts as one that changes things, so each of a store's actions waits, product lookups included. The person who asked may approve their own call when their role reviews approvals, unless the agent setsseparateApprover. They still can't run a flow or call a tool directly (What an Ask may do).
- The runtime image has a directory for uploaded files.
/var/lib/kindgi/artifactsbelongs to the server's user (uid10001), so a Docker named volume mounted there takes that owner, forKINDGI_ARTIFACTS=local:/var/lib/kindgi/artifacts. Eachlocal:target is checked at start, and a directory the server can't write in stops it, naming the server's user id. - A
gcs:bucket is checked at start. The runtime refuses to start when the server's identity lacks a permission it needs, naming each one, or when the artifacts bucket has a retention policy or a default event-based hold, since no tenant purge could delete a file there. It warns when the bucket keeps deleted files restorable (soft delete) or has a lifecycle rule that can delete files it still names.STORAGE_EMULATOR_HOSTworks in development only (KINDGI_DEV). - The WordPress plugin's Ask page opens a conversation. Since the plugin
came out in Kindgi 0.1.9, a question to one of the site's own agents was
refused for everyone the site signs in. The plugin named the site's project
when it opened the conversation, and naming a project needs
writeon it, which a site's people never get. Now it names no project for the site's own agents, so Kindgi opens the conversation in the agent's own project, the site's. For an agent another project shares with the site's, it names the site's project, where calling the agent is enough. To get the fix, uploadkindgi-0.2.0.zipfrom the 0.4.0 release over the plugin you have. - Two fixes in the WordPress plugin's Ask and Inbox pages. A saved
conversation no longer opens with "nullnull" above it. An approval
opened from its email link after it was decided no longer shows twice,
under From your link and again under Decided by you lately: it
opens in the Inbox under the list that holds it, Waits for you,
Waits for others or Decided, and From your link shows only
one that none of them holds. Both fixes are in the same
kindgi-0.2.0.zip. - A test run's replays no longer send
run.finished. Before, an endpoint that takesrun.finishedgot one for each replay of a test run. A run inside another run still sends none (Webhook events and deliveries). - A pin's release gate reads only a completed test run. A comparison
cancelled or failed part way kept the summary of the cases it got
through, and the gate checked it as if the run had completed. Now
POST /v1/agents/{agentId}/pinned/pinand.../pinned/checkrefuse atestRunIdwhose run didn't complete (400 bad-input). - OpenAI-compatible providers send a model's registered
maxOutputTokenswhen the call sets none. Before, a cap registered on a model didn't apply on OpenAI, OpenRouter, Groq or a self-hosted OpenAI-compatible server. Theopenai,groqandopenrouterpresets register their models with a cap, so calls through them now send it. - The CLI runs git, and
kindgi dev's Linux sandbox its helpers, by their full path onPATH. Agit, or ansh,bwrap,mktemp,sedorrm, in the pack's folder no longer runs in their place. When one isn't onPATH,kindgi devstops withspawn <name> ENOENT. kindgi deploysays when nothing new was deployed. When the server answers from its record of an earlier request with the sameIdempotency-Key, it says nothing new was deployed, where it printed "Deploy complete." under its replay note. Its JSON addsidempotentReplay: true.- The deploy banner and
KINDGI_PACK_ROUTING's description say a call goes to the newest deployment in the run's project, not the tenant's newest. - The Azure Container Apps guide keeps the registry login token off the
command line. It pipes the token to
docker login's stdin in place of a plainaz acr login, as the module'supgrade.shdoes (Azure Container Apps). - The woocommerce template's README starts with a question about your orders, and its refund example uses a test order, since a refund of up to 100 runs with no approval when you ask for it.
- A rotated secret's old version resolves until its grace period
ends. With
kindgi secrets rotate --revoke-old-after, the old version stopped resolving at once, as if revoked then. It now resolves until the time the rotation set, and revoking it in that window ends it at once. - Under
kindgi dev, a pack tool markedresultIsOutsideDatahas its results treated as outside data again.kindgi devdropped the mark, so the model got the tool's results as plain text. A deployed pack had it right. - The Retire dialogs say where a retired one is listed. They, and the notice on a flow, agent or tool whose every version is retired, say it's listed under Show retired. They said it stayed listed as retired, while the tables and lists hid it.
Changed
Section titled “Changed”-
0.4.0 renames its ideas, and keeps no old name. A judgment is a correction, a judge class a corrector group, the judging queue the expert queue, an eval suite a test set, an eval run a test run, choosing what a project runs a pin, an improvement pass an Improve run, a proposal a suggested change, and a gate policy a release gate. Routes, fields, values, error codes, schemas, the clients' names, the CLI's commands and flags, and the docs' addresses all change, as the lists below say. Environment promotion keeps its name:
kindgi promote,POST /v1/deployments/{deploymentId}/promotionsandclient.deployments.promote. -
A judgment is now a correction.
/v1/judgmentsis/v1/corrections, and/v1/judgments/{judgmentId}/unregisteris/v1/corrections/{correctionId}/remove. The retention domainjudgmentiscorrection(POST /v1/retention/sweep/correction).judgmentIdandjudgmentIdsarecorrectionIdandcorrectionIds.judgmentCount,runsWithJudgmentsandanyJudgmentarecorrectionCount,runsWithCorrectionsandanyCorrection. An answer'sjudgmentsiscorrections, a comparison summary'scorrections.judgmentsiscorrections.results, a comparison case'sjudgedItemsiscorrectedItems, and achanges.newentry'sjudgediscorrected.- The error code
judgment-not-foundiscorrection-not-found. JudgmentandJudgmentWithCopiesareCorrectionandCorrectionWithCopies. The{ calls, notCalled }value that was calledCorrectionisExpectedDecisions, graded asExpectedDecisionsResult.Judged*names areCorrected*, andUnregisterJudgmentResultisRemoveCorrectionResult.client.judgmentsisclient.corrections, and itsunregisterisremove.kindgi judgments add|list|show|unregisteriskindgi corrections add|list|show|remove.
-
Judge classes are now corrector groups, the judging queue is the expert queue, and judging rules are queue rules.
/v1/judge-classesis/v1/corrector-groups, with{correctorGroupId}in its paths./v1/projects/{projectId}/judging-queueis/v1/projects/{projectId}/expert-queue, and/v1/projects/{projectId}/judging-rulesis/v1/projects/{projectId}/queue-rules, with the same paths below them. The retention domainjudge_classiscorrector_group.judgeClassIdiscorrectorGroupId. A correction, a corrected item and a test case's item sayexpertwhere they saidrestricted.classWeightsisgroupWeights, and its valuerestricted-onlyisexperts-only. A release gate'sonlyRestrictedClassesisonlyExpertGroups, and its check is namedgroupWeights.expertsOnly. The expert queue's statejudgediscorrected, as is a rule result'sjudgedcount; progressbyClassisbyGroup, andwantedClassIdsiswantedGroupIds.- Error codes starting
judge-class-startcorrector-group-, codes startingjudging-rule-startqueue-rule-, and the otherjudging-codes startexpert-queue-. JudgeClass*names areCorrectorGroup*,JudgingRule*names areQueueRule*, and the judging queue'sJudging*names areExpertQueue*. In the Python client,RestrictedisExpert.client.judgeClassesisclient.correctorGroups,client.projects.judgingQueueisclient.projects.expertQueue, andclient.projects.judgingRulesisclient.projects.queueRules.kindgi judge-classesiskindgi corrector-groups,kindgi judging-queueiskindgi expert-queue, andkindgi judging-rulesiskindgi queue-rules.--classis--group,--clear-classis--clear-group, and--class-weightsis--group-weights.
-
Eval suites are now test sets.
/v1/eval-suitesis/v1/test-sets, with{testSetId}in its paths and the same paths below it,runstoo.suiteIdistestSetIdwherever it names a test set, andsuiteVersionistestSetVersion. A test set's and a test run's kindjudgediscorrections. A release gate'scomparison.suiteiscomparison.testSet, and so is its check's name; a comparison's summary saystestSetwhere it saidsuite. The retention domain and the authorization resource typeeval_suitearetest_set. Areference-out-of-scopeissue names a test set with the kindtest-set, where it saidsuite.- Error codes starting
eval-suite-starttest-set-. EvalSuite*names areTestSet*,EvalKindisTestSetKind,EVAL_KINDSisTEST_SET_KINDS, andJudgedEvalCase,JudgedEvalCaseCollectionPageandJudgedEvalCaseCorrectionareCorrectedTestCase,CorrectedTestCaseCollectionPageandCorrectedTestCaseCorrection.- The test set file's schema is
@kindgi/specs/test-set.schema.json(waseval-suite.schema.json). A file whose$schemanameshttps://kindgi.com/schemas/v1/eval-suite.schema.jsonneedshttps://kindgi.com/schemas/v1/test-set.schema.json. Itskindtakescorrections, as the API does, and its reference page is Test set. client.evalSuitesisclient.testSets.kindgi eval-suitesiskindgi test-sets,--suiteis--test-set, and--suite-versionis--test-set-version.kindgi exports createwrites them astest-setsandtest-set-versions.
-
Eval runs are now test runs.
/v1/eval-runsis/v1/test-runs, with{testRunId}in its paths;cancel,eventsandrescorekeep their paths.POST /v1/test-sets/{testSetId}/runsstill starts one.- A test run's own id is
testRunIdwhere it wasrunId: in the start and rescore answers, the run view and the list rows. Ids of agent runs, such as a case'srunIds, keep their names.evalRunIdistestRunIdwherever it names a test run: in an agent pin's body, in a run's replay marker ({ of, testRunId }), in a replay's provenance, and in the/v1/runsfilter. - The stream's events
eval-run.completed,eval-run.failed,eval-run.cancelled,eval-run.case-completedandeval-run.case-failedaretest-run.*, with the same endings. The compliance evidence kindeval-runistest-run, andGET /v1/compliance/evidence?kind=answers400for a kind that is neither built in nor named by the classifier, such aseval-run, where it answered an empty page. - Error codes starting
eval-run-starttest-run-. EvalRun*names areTestRun*.EvalComparison,EvalBaseline,EvalOverrides,EvalSample,EvalReadsandEvalClassWeightsareTestRunComparison,TestRunBaseline,TestRunOverrides,TestRunSample,TestRunReadsandTestRunGroupWeights.client.evalRunsisclient.testRuns.kindgi eval-runsiskindgi test-runs, and--eval-runis--test-run, onkindgi agents pinandkindgi runs list.kindgi exports createwrites them astest-runs.
-
Choosing what a project runs is a pin, for agents as for flows and tools.
- An agent's
/promotionsis/pinned/pin,/promotions/checkis/pinned/check, its list of promotions and/promotions/{promotionId}are/pin-historyand/pin-history/{changeId},/liveis/pinned,/live-versionsis/pinned-versions, and/live/unpinis/pinned/unpin./live/rollbackis removed: going back is a pin of an earlier version, through the same release gate and approval. promotionIdischangeId: on a pinned version, in a deployment's pin gate and in a refused pin'sdetails. A pin's statuspromotedispinned, and the check's outcomewould-promoteiswould-pin; a pin's action ispinorunpin.- What an agent resolves to:
via: 'live'is'pinned', andliveScopeispinnedScope. So are a run'sviaand a queue rule'swhen.versionsvalue; awhen.versionsentry that is neither an exact version, such as1.2.0, norpinnedis refused (400). A test run comparison's baseline{ live: ... }is{ pinned: ... }, a compared version'sviavalueliveispinned, and the CLI's--baseline liveis--baseline pinned. - Unregistering a pinned agent version answers
agent-version-pinned(wasagent-version-live), as for flows and tools, and lists the scopes it's pinned in underpinned(waslive). The permissionpromoteon an agent ispin. The audit kindsagent-promotion,agent-promotion-refused,agent-live-unpinnedandagent-live-pin-inactiveareagent-pinned,agent-pin-refused,agent-unpinnedandagent-pin-inactive, andagent-rollbackis gone. promotion-not-found,promotion-supersededandpromotion-gate-unsupportedarepin-not-found,pin-supersededandpin-gate-unsupported, andlive-scope-spans-environmentsispin-scope-spans-environments, the code a flow or tool pin answers.nothing-to-roll-backis gone with the rollback route. Environment promotion's codes keep their names.Promotion,PromotionPageandPromotionCheckarePin,PinPageandPinCheck.PromoteBodyandUnpinBodyareAgentPinBodyandAgentUnpinBody.LivePin,LivePinListandLiveVersionResolutionareAgentPinnedVersion,AgentPinnedVersionListandAgentPinnedVersionResolution. An agent's pin scope isAgentPinScope, made of thePinScope*schemas flows and tools use, withPinScopeSegmentfor a segment. In@kindgi/types,LiveScopeisAgentPinScope. In the Python client,LiveScopeOrg,LiveScopeProject,LiveScopeSegmentandLiveScopeTenantarePinScopeOrg,PinScopeProject,PinScopeSegmentandPinScopeTenant, andLiveScopeUnrecognizedisAgentPinScopeUnrecognized.client.agents.pinnedhasresolve,list,pin,check,unpin,historyandgetChange;client.agents.promotionsandclient.agents.liveare removed. Its types areAgentPinnedClient,AgentPinnedWhere,AgentUnpinInputandListPinHistoryFilter.kindgi agents promoteiskindgi agents pin,promotions list|getispin-history list|get,liveispinned, andlive-versionsispinned-versions.kindgi agents rollbackis removed.<promotion-id>is<change-id>.
- An agent's
-
A deployment promotion's make-live is now a pin. A promotion's
makeLiveispin: it pins each agent version the promotion carries in the target project, each through its scope's release gate, and each flow version it carries. The answer lists the carried agents underpinned(waslive), besidepinnedFlows. A write error after some were pinned lists them inerror.details.pinned(waserror.details.live) anderror.details.pinnedFlows.DeploymentLivePinandDeploymentLivePinGateareDeploymentPinnedAgentandDeploymentPinGate.kindgi promote --make-liveiskindgi promote --pin, and--waitgoes with--pin; its output lists the carried agents' pins underAgent pins in <env>:(wasLive in <env>:).kindgi dev's line for a block version pinned in the console sayspinned:(wasmade live:). -
Improvement passes are now Improve runs.
/v1/improvement-passesis/v1/improve-runs, with{improveRunId}in its paths, andcancelkeeps its path.POST /v1/proposals/improveisPOST /v1/improve-runs, andPOST /v1/proposals/improve/estimateisPOST /v1/improve-runs/check.passIdisimproveRunIdwherever it names an Improve run: on a schedule's fire and on a suggested change'smadeBy. A suggested change'sdrafterismadeByand itshypothesisiswhy, in the body that creates one and in an Improve run's comparisons too. An Improve run's outcomeproposedissuggested. A test run'spassCountkeeps its name: it counts the cases that passed.improvement-pass-not-foundandimprovement-pass-finishedareimprove-run-not-foundandimprove-run-finished.ImprovementPass*names areImproveRun*. The start body isStartImproveRunBody(wasImproveBody), for a start and a check, and the check's answer isImproveRunCheck(wasImprovementPassEstimate).SuggestedChangeDrafterisSuggestedChangeMadeBy.client.improveRunshasstart,check,list,getandcancel;client.improvementPassesandclient.proposalsare removed. Their inputs areStartImproveRunInputandCheckImproveRunInput, and@kindgi/sdkexportsImproveRunsClientwhere it exportedProposalsClient.kindgi improve runs startstarts one (waskindgi proposals improve), andkindgi improve runs list,getandcancelreplacekindgi proposals passes;kindgi proposalsis removed.<pass-id>is<improve-run-id>.kindgi exports createwrites them asimprove-runs.
-
Proposals are now suggested changes.
/v1/proposalsis/v1/suggested-changes, with{suggestedChangeId}in its paths..../requestis.../pin..../rollbackis removed: going back is pinning the agent's earlier version.proposalIdissuggestedChangeIdwherever it names a suggested change: on a version'sderivedFrom, on an Improve outcome, and in a refused gate'sdetails. A suggested change's statuspromotedispinned. The headerX-Proposal-DedupedisX-Suggested-Change-Deduped.- Error codes starting
proposal-startsuggested-change-. Proposal*andFixProposal*names that stay areSuggestedChange*, andFixProposalIdisSuggestedChangeId. A suggested change rolled back by the removed route reads aspinned.client.suggestedChangesholds suggested changes, and itsrequestispin. Itsrollbackis removed: pin the agent's earlier version withclient.agents.pinned.pin.kindgi proposalscommands arekindgi suggested-changes, whose verbs change too (below), androllbackis removed:kindgi agents pinwith the earlier version puts it back.kindgi exports createwrites them assuggested-changes.
-
A gate policy is now a release gate.
/v1/gate-policiesis/v1/release-gates, with the same paths below it, and an agent's/gate-policyis/release-gate. The operation idsgatePolicies.*andagents.gatePolicy.resolvearereleaseGates.*andagents.releaseGate.resolve, under the tagrelease-gates.- A release gate's
policyIdisreleaseGateId. The release gate a pin names isreleaseGate(waspolicy): on a pin and in the pin history, in a pin check's answer, in a refused pin'sdetails, in apin-gate-unsupportedanswer, in a deployment promotion's pin gate, and in the answer ofGET /v1/agents/{agentId}/release-gate. - A test run comparison's
weightedYesShareispassRate, and itsjudgedCoverageiscaseCoverage. So are the metric names in a release gate's spec, and theobjectiveof an Improve run, a schedule's Improve run and the Improve run webhook event (passRate, the default, orweightedPrecisionAtK); the CLI's--objectivetakes the same values. The gate's checkbaselineIsLiveisbaselineIsPinned. gate-policy-not-found,gate-policy-already-registered,gate-policy-scope-taken,gate-policy-scope-changed,gate-policy-scope-unpinned,gate-policy-needs-pinandgate-policy-descendant-unpinnedarerelease-gate-not-found,release-gate-already-registered,release-gate-scope-taken,release-gate-scope-changed,release-gate-scope-unpinned,release-gate-needs-pinandrelease-gate-descendant-unpinned, with the same statuses and bodies.- A spec's
approvals.forRollbackis gone, since going back is a pin, which the gate checks: the key is refused as any other unknown key is. GatePolicy,GatePolicyPage,GatePolicyRef,GatePolicyResolution,GatePolicySpecandPublishGatePolicyBodyareReleaseGate,ReleaseGatePage,ReleaseGateRef,ReleaseGateResolution,ReleaseGateSpecandPublishReleaseGateBody.client.gatePoliciesisclient.releaseGates, andclient.agents.gatePolicyisclient.agents.releaseGate, with the typesReleaseGatesClient,ReleaseGateVersionsClient,AgentReleaseGateClient,ReleaseGateFilterandPublishReleaseGateInput.kindgi gate-policiesiskindgi release-gates,kindgi agents gate-policyiskindgi agents release-gate,<policy-id>is<release-gate-id>, and--policy-versionis--release-gate-version. In an export, the kindsgate-policiesandgate-policy-versionsarerelease-gatesandrelease-gate-versions. Don't resume an export an earlier CLI started: run it again into a new folder, since resuming writes the new kinds beside the old ones.
-
The improve guides moved, with no redirects. The pages under
guides/evals/are underguides/improve/, so old links to them don't open. Four have new names:judge-a-runs-outputiscorrect-a-runs-output,propose-a-changeissuggest-a-change,judging-referenceisexpert-queue-reference, andlive-versions-referenceispinned-versions-reference. The 0.3 pages stay under/v0.3/. -
For a runtime of your own, built on
@kindgi/api: the bindings take the new names too.createApp's inputs:agentReleasesisagentPins,judgmentRegistryiscorrectionRegistry,evalSuiteRegistryistestSetRegistry,evalRunBindingistestRunBinding,judgingQueueisexpertQueue,improvementPassesisimproveRuns, andevalCaseStoreisfrozenCaseStore. Each is optional, so in JavaScript an old name is ignored without an error, and the runtime runs as if that binding were absent. New optional inputs serve what's new in 0.4.0:toolFiles,pinFiles,testSetFreeze,blockUse,blockVersionPullRequestsandenvCloudSecrets. Each one's type says what happens without it. For example, withouttestSetFreeze, making or checking a suggested change answers501 suggested-change-check-unsupported, and withoutenvCloudSecretsthe cloud secrets routes answer501 cloud-secrets-unsupported.- Pins: implement
AgentPinnedVersionBinding(wasLiveVersionBinding) andPinBinding(wasPromotionBinding), withAgentPinBindingsandAgentPinGateDeps(wereAgentReleaseBindingsandAgentReleaseGateDeps).AgentPinBindingsholds them aspinnedandchanges(wereliveandpromotions). Their types arePin,PinStatus,PinAction,PinError,PinErrorCode,PinRequestInput,ListPinHistoryInput,AgentPinInput,AgentUnpinInput,AgentPinnedVersion,AgentPinResolutionandAgentPinResolveInput;PromotionActorandPinActorare onePinActor, andliveScopeCoordinatesisagentPinScopeCoordinates.rollbackandRollbackInputare gone, and an unregister a pin refuses answerspinned(waslive). A run'sliveScopeispinnedScopein@kindgi/runtimeand@kindgi/agents. - Release gates: implement
ReleaseGateBinding(wasGatePolicyBinding) asAgentPinBindings'releaseGates(wasgatePolicies), withReleaseGateError,ReleaseGateErrorCode,ReleaseGateListInput,ReleaseGatePublishInputandReleaseGateVersionInput. - Latest:
AgentPinBindings.latest, aLatestBinding, is required, and so areAgentPublishInput.madeForandAgentRegistryBinding.markLatest.whatRunsandwhatRunsByProjectanswer a scope's pin, else its Latest. - Test runs and test sets:
EvalSubjectInvokerisTestRunSubjectInvoker, andEvalCaseStoreBinding,EvalCasePutInput,EvalCaseListInputandEvalCasePageareFrozenCaseStoreBinding,FrozenCasePutInput,FrozenCaseListInputandFrozenCasePage. - Corrections:
CorrectionRegistryBindinggainsupdate,counts,correctionsByIdsandapplyRunOutcome, and the test set'stestSet,listCases,getCase,runCopies,addCaseandretireCase, all required. Its class methods are group methods:createGroup,listGroups,getGroup,updateGroupandunregisterGroup. It loseslistJudgedRuns, and itsunregistersets the status toremoved.sortAtSaveandplanChangeare exported, so every store sorts and changes a correction by the same rules. - Suggested changes:
SupervisorBinding'slistProposals,getProposal,createProposalandrecordProposalarelistSuggestedChanges,getSuggestedChange,createSuggestedChangeandrecordSuggestedChange. - Pack services:
SystemDeploymentsBinding.listReadyis new and required. It answersGET /v1/system/deployments?endpoint=ready(client.systemDeployments.list('ready')): the deployments whose endpoint isreadyand whose pack service stays, across tenants, oldest first, with the same paging asendpoint=missingandendpoint=retire. @kindgi/tools:latestVersionishighestVersion, since it answers the highest version, which isn't always what a project runs.
-
A correction says whether a run's decisions and its answer were right, and no old field is kept.
POST /v1/correctionstakesdecisionsandanswer, eachrightorwrong, anditems, at least one of the three. Wrong decisions needshouldCall([{ tool, args? }], withargsonly when the inputs matter) ormustNotCall(tool ids). A wrong answer needsshouldSayorwhy.items([{ key, pointer?, rank?, verdict }]) is for an answer that is a ranked list.item,verdict,reasonandcorrectionare gone, and a body with one is refused (400), naming its new field. A second correction of a run by the same caller, for the sameparticipantId, replaces the first (Correct a run's output). -
A correction is sorted when it's saved, and moves until it's fixed. Wrong decisions go to the agent's owner (
with-owner), a wrong answer or item goes to Improve (open), and a correction with nothing wrong isfixed, asrecorded-right. An app end user's correction (one with aparticipantId, and not an expert's) staysopenand unsorted, unless a project admin setssortEndUserCorrections: trueonPATCH /v1/projects/{projectId}. A correction answersstatus,sortedTo,sorted,link,fixedIn,statusNoteandupdatedAt.PATCH /v1/corrections/{correctionId}(client.corrections.change) sorts it again, changes its status, or both: it needspublishon the agent, or, for an agent more than one project serves,writeon the correction's project. A change its status doesn't allow answers409 correction-status-change-not-allowed, withdetails: { from, to }. Removing a correction, by its author or an admin of its project, makes itremoved.GET /v1/correctionsfilters bystatus(not-fixedforopen,being-fixedandwith-owner),sortedTo(nonefor the unsorted),from(experts,end-usersorall),madeBy=me,sinceanduntil, andverdictis gone.GET /v1/corrections/counts(client.corrections.counts) counts a project's corrections, or one agent's, by status. -
kindgi correctionstakes a correction's parts as the API names them.kindgi corrections addtakes--decisions=right|wrong, with--should-call=<tool>[:<json-args>]and--must-not-call=<tool>(each repeatable) for wrong ones,--answer=right|wrong, with--should-say=<text>for a wrong one,--why=<text>,--group=<corrector-group-id>, and--item=<key>with--yesor--noas before.--correction,--reasonand--item=answerare gone. Each call still adds to your correction of the run: a part it gives replaces what you said about that part. The newkindgi corrections set <correction-id>takes--sorted-to=improve|developer|owner,--status=open|being-fixed|wont-fix,--linkfor what fixes it, and--reason, whichwont-fixneeds.kindgi corrections listloses--verdict, and takes--status,--sorted-to,--from=experts|end-users|alland--since=<time>. It lists removed corrections only when--statusnamesremoved. -
client.supervisoris gone from the TypeScript client. Every method on it threwnot-yet-wired: useclient.suggestedChangesandclient.observations. With it goSupervisorClient,SupervisorProposalsClientand their input types,SupervisorSpec,Supervisor,DryRunCriterion, and the proposal result types no method returned. The error codesupervisor-header-missing, which the API never sent, leaves the API's codes and the TypeScript, Python and Java clients. -
The TypeScript client's
client.observationskeeps onlyquery.recordRunandpatterns, which threwnot-yet-wired, are gone, withPatternsInput. -
The TypeScript client's list pages drop
items. A list call answers the API's page alone:data,hasMoreandnextCursor.itemswas deprecated before and is gone now: readpage.data. -
A run that names no version gets the agent's Latest in its project, no longer the highest version its project reaches. That holds where no pin covers the run's scope. Latest moves only when a deployment into the project ships a version, when a person publishes a full version (
POST /v1/agents), or when a person adds a suggested change's version as Latest. A pin never moves it. A project where no version has a time yet has no Latest, and refuses such a run: "none is pinned there, and none is its Latest". The highest version still numbers the next one, andGET /v1/agents/{agentId}still answers it.GET /v1/agents/{agentId}/projectssays, for each project, what a run that names no version gets there (runs: the version, since when, and the pin or deployment behind it) and why (follows:pinorlatest), the pins on segments inside it (segments), and the agent'shighestversion. What serves a scope, a pin's check, a flow publish's default agent pin and a trigger'stoolsAllowedUnattendedcheck all read Latest the same way: a covering pin, else Latest. -
A pin into a scope where nothing runs yet is refused. Where no version of the agent runs (no pin, and no Latest), a pin answers
409 nothing-runs-in-scope, or409 project-suspendedwhen the project is suspended, since there's nothing to measure it against. It was measured against the highest version. The TypeScript client throwsConflictErrorfor it. -
A trigger's
toolsAllowedUnattendedis refused while nothing it checks runs in the trigger's project. A schedule, webhook or mail trigger whose list names a tool its target doesn't call answers400 bad-inputwhen no version of the agent runs there (no pin, and no Latest), since its tools can't be checked. A flow is refused the same way when an agent step names no version and no flow version pins one. NameagentVersion, or deploy or publish a version into the project first. The check read the agent's highest version before. -
A pin answers
{ pin, testRuns, fixed, reopened }, and an unpin answers201.POST /v1/agents/{agentId}/pinned/pinanswers the pin change underpin, the test runs that check it, and the corrections a reused test run changed (PinAnswer), still with201, or202while it waits for an approval.POST /v1/agents/{agentId}/pinned/unpinanswers the same shape with201, where it answered200with the change alone.POST /v1/suggested-changes/{suggestedChangeId}/pinanswers the same shape, with the suggested change undersuggestedChange(SuggestedChangePinAnswer).agents.pinned.pin,agents.pinned.unpin,suggestedChanges.pin,kindgi agents pin,kindgi agents unpinandkindgi suggested-changes pingive the same shapes. -
A pin that would take a project off Latest is refused unless you say so. A project or segment pin of a project that follows Latest, or a tenant or org pin over one, answers
409 pin-stops-latest, even when the version doesn't change, with each project and the version it runs now indetails.projects. Nothing is recorded. SendstopFollowingLatest: trueto pin anyway, or--stop-following-latestonkindgi agents pinandkindgi suggested-changes pin; the change then recordsstoppedFollowingLatest: true. Such a pin went through before. A deployment promotion'spinis never refused this way. -
Kindgi names its own test runs, so a start can't.
POST /v1/test-sets/{testSetId}/runsrefuses acorrelationIdthat starts withpin:orlatest:(400 bad-input): those name the test runs a pin or Latest moving starts. -
A suggested change's
fixesare checked when it's made. Each id must be a correction in the suggested change's own project:POST /v1/suggested-changesrefuses an unknown id, or another project's, with400 validation-failed, listing them indetails.fixes, and makes nothing.fixesnames at most 100 ids (400 bad-input). -
An Improve run works in one project, and keeps a change only when it passes more of the cases and fails none that passed.
POST /v1/improve-runstakes{ agentId, projectId, tiers?, model?, candidates?, budget?, objective?, groupWeights? }.projectIdis required, and a body that sendsscope,testSetIdorfromVersionis refused (400 bad-input), naming the field. It starts from the version the project runs, takes the project's open corrections sorted to Improve, and searches and proves on the project's test set. A change is kept only when its proof, on every case at the reference's repetitions, passes more cases than the version it started from and fails none that passed. The cheaper path for model-settings changes is gone.GET /v1/improve-runstakesprojectIdandstatus(Improve an agent). -
An Improve run checks it's ready before it starts.
POST /v1/improve-runs/checkanswers{ ready, startsFrom, items, estimate, month }:itemslists what's missing, fromwording,settings,test-cases,permission,one-at-a-timeandproject, each with itsfix. The check'sestimatedCostUsd,maxCostUsdandbasismove underestimate({ costUsd, maxCostUsd, basis }), andmonthis this month's spend against the Improve schedule's cap. A start that isn't ready answers409 improve-not-ready, with the missing items indetails.items, and a second start for the same agent and project answers409 improve-run-running, withdetails.improveRunId. A start no longer answersvalidation-failedforno-tunable-keysorno-pinned-prompt-block, andproposal-needs-pinis gone. -
An Improve run's record changes.
candidatesEvaluatedistried. It gainsprojectId,startsFrom({ version, follows }),testSetVersion,setAside({ cases, of }) andtakes, the correction ids it took, and losesfromVersion,scopeandtestSetId;groupWeightsis always there. Itsoutcomeissuggested,nothing-better(wasnothing-found, withreasonand an optionalholdOut),cost-cap(new, withspentUsd) orfailed. A comparison'spartcan beall, for the proof. Theimprove-run.finishedwebhook event carries the same shape. -
An Improve schedule is for one agent in one project. Its target is
improve: { agentId, projectId }, one per agent and project (409 schedule-exists, withdetails.scheduleIdanddetails.triggerId), and a segment or tenant scope is gone. Its input is{ corrections, from, runCapUsd, monthCapUsd, tiers?, model? }, with the defaults 5,experts, 5 and 20 (monthCapUsdwasmonthlyCapUsd).threshold,candidates,budget,objectiveandgroupWeightsare gone, and an option it doesn't have is refused. A schedule at its month's cap staysactiveand says until when (pausedUntil, withpausedReason: 'month-cap'). One whose owner losespublishon the agent is paused at its next fire (statusReason: 'owner-lost-publish'), and saving it with a new owner resumes it. Registering, changing, pausing, resuming, firing or unregistering one takeswriteon the project andpublishon the agent; an admin of its project may also pause or unregister one withoutpublish. -
The TypeScript client and the CLI follow.
StartImproveRunInputandCheckImproveRunInputtakeprojectId(required),tiers,objective,groupWeights,model,candidatesandbudget, andImproveRunsListInputtakesprojectIdandstatus. A409 improve-not-readyis aconflictwhosefields.itemslists what's missing.kindgi improve runs starttakes--project(required) and--check, which prints the readiness items, the estimate and the month, starts nothing, and exits3when it isn't ready;--tierrepeats.--tenant,--org,--segment,--pass-project,--test-setand--from-versionare gone.kindgi improve runs listtakes--projectand--status.kindgi schedules create --improveneeds--project, and its--segmentis gone. -
The Anthropic and Gemini adapters throw
ModelProviderError. For a response that refuses a call, they throw the shared error from@kindgi/adapter-model-shared, as the Bedrock, Azure OpenAI and OpenAI-compatible adapters do. Itskindcomes from the status and the provider's words (invalid-request,auth,rate-limited,unavailable,context-too-longorcontent-filter, andnetworkfor Anthropic's failed connection), with itsstatus, and its message is the same as before. The provider SDK's own error (Anthropic'sAPIError, Gemini'sApiError) is now itscause: code that checked the thrown error's type checkscauseinstead. An abort, and Gemini's failed connection, are thrown as before. -
A stdio MCP server's secrets go by reference, and a credential in
config.envis refused. Give a stdio endpoint its secret variables insecretEnv, each name with the secret its value is read from when the runtime starts the server, as in"secretEnv": { "GITHUB_TOKEN": { "envName": "production", "name": "FILES_GITHUB_TOKEN" } }(1 to 16 of them). The value is never stored with the endpoint or answered. Registering an endpoint with a credential-named variable inconfig.env, such asGITHUB_TOKEN,OPENAI_API_KEYorDB_PASSWORD, is refused (invalid-mcp-endpoint, reasoncredential-in-env), naming the variable and thesecretEnvthat replaces it; a loneKEY, as inCACHE_KEY, doesn't count.secretRefon a stdio endpoint is refused too (secret-ref-on-stdio), since a stdio server gets no headers, andsecretEnvon an HTTP endpoint (secret-env-on-http). Everyconfig.envvalue reads back as"[redacted]", its name kept, on endpoints registered before too, so an export holds the names and not the values. Aconfig.envvalue of exactly"[redacted]"is refused (invalid-stdio-env), so registering an endpoint again from what itsGETanswers fails until its values are put back, or its secrets move tosecretEnv. A value with a NUL, and a name that's empty or holds=or a NUL, are refused too. Endpoints registered before keep working, andkindgi doctor's new checkmcp-envlists each stdio endpoint that keeps a credential inconfig.env, or asecretRef, with the fix. If you go back to an earlier runtime, an endpoint registered withsecretEnvstarts without those variables (MCP servers). -
A provider registration with a field it doesn't take is refused.
POST /v1/providersanswers400 invalid-provider, with reasonunknown-model-fieldorunknown-metadata-field, naming the field and the fields a model takes. Before, such a field was dropped without a word, so a misspelledthinkingregistered a model that doesn't think. Registrations stored before aren't checked again. -
A suggested change is made for one project, and checked on that project's test set.
POST /v1/suggested-changestakesagentId,projectId,block, andvaluesfor a settings block ortemplatefor a prompt block, withwhyandfixes(at most 100 correction ids from the project). It's built on the version the project runs, and its check starts at once: its version and the one it's built on run the same cases of the project's test set.POST .../checkchecks it again, in place ofevaluateandrescore, which are gone.fromVersion,scope,tier,changeandevidenceare gone from the body and the answer, andcandidate,evaluation,promotionandrolledBackfrom the answer. The list takesagentId,projectId,statusandmadeBy, nottieror a scope. Its status ischecking,check-failed,ready,waiting-for-second-person,pinned,added-as-latestorwithdrawn. One made at 0.3.x for a tenant, an org or a segment can only be withdrawn (409 suggested-change-not-for-a-project). In the TypeScript client,createtakes the new body,checkreplacesevaluateandrescore, andProposalTierandEvaluateProposalInputare gone from it.kindgi suggested-changes createreplacesdraft: it needs--projectand takes--whyand--fixes, once per correction, and--from-version,--tenant,--org,--segmentand--tierare gone.checkreplacesevaluate(Suggest a change, and test it). -
Deriving an agent version through the API is gone.
POST /v1/agents/{agentId}/versionsis removed, withclient.agents.versions.derive,DeriveAgentVersionInputandkindgi agents derive. A suggested change makes such a version now, and checks it. A version derived before keeps itsderivedFrom. -
Test sets aren't built from corrections any more: an agent's corrections are its test set.
POST /v1/eval-suites/{suiteId}/versions/from-judgments,client.evalSuites.buildFromJudgments(build_from_judgmentsin the Python client) andkindgi eval-suites from-judgmentsare removed, and so is the error codetest-sets-not-supported. Acorrectionstest set built before still reads by its id, butGET /v1/test-setsandkindgi test-sets listlist one only withkind=corrections. A test set id that starts withagent.is kept for an agent's own test set:POST /v1/test-setsrefuses one (400 bad-input), and the TypeScript client refuses it before sending. A test set published under such an id before keeps reading and running, but takes no new version: publish it under another id.CorrectedTestCase'srunIdis required. -
A block an agent version uses for its model settings takes model settings only.
POST /v1/blocksrefuses a new version of such a block when its values aren't model settings, or name a model the agent version names too (400 validation-failed, naming the agent version). -
A deploy that would put back an older block stops. Before anything is published,
POST /v1/deploymentscompares each of the pack's data blocks with the newest version that runs now in any project of the pack's agents. When the pack's file is older, the deploy answers409 deploy-would-put-back-older-blocks, lists each block indetails.blocks, and writes nothing. To put one back on purpose, name it in the body'sreplace([{ blockId, reason }]), or runkindgi deploy --replace=<block> --reason=<text>.POST /v1/deployments/check(client.deployments.check) answers the same with nothing written, andkindgi deployasks it before it builds an image. A deployment promotion withpinruns the same check against the target project, andkindgi promote --pintakes--replacetoo. -
The Cloud Run module's one-pack-service variables are gone.
pack_image,pack_min_instances,pack_envandpack_secret_env, and the outputpack_service_url, are removed: each deployment has a pack service of its own, and the pack's env comes from Kindgi (kindgi env set).name_prefixcan't bekpor start withkp-.pack_concurrencyandpack_max_instancestake whole numbers from 1 to 1000,pack_timeoutwhole seconds from"1s"to"3600s", andpack_cloud_sql_instancesat most 10. New:pack_secret_readers, the Secret Manager secrets a pack's env names as cloud secrets, andorchestrator_key_version, which isnullby default and leaves the pack orchestrator out until it's set, with the outputorchestrator_key_steps.service_accountsnamesserver,packandorchestrator(Cloud Run module reference). -
A new tenant's default project is named "First Project". One made before keeps "Default". Messages, help and docs say "the default project" for the one with
isDefault: true. To find it, useisDefault,GET /v1/projects/defaultorclient.projects.getDefault(), never the name or the slugdefault. -
A write whose database fails answers
500, not404or409. Unregistering or reinstating an agent, flow, tool or test set version, deleting an env value, and unregistering an MCP endpoint, a provider or a reviewer answered404when the database failed, as if what they named weren't there. Publishing a test set answered409, as if it were already there. They now answer500and change nothing. A session whose activity can't be recorded is logged atWARN, and its next request records it again. -
With per-deployment routing, an older build keeps its pack service while something can still call it. A deployment's service stays while a version it ships is registered, or held: a pin still reaches it, or a run in flight uses it. Then it's superseded and retired. Before, every version a deployment shipped counted, so a service went only once a later deploy shipped the same versions.
GET /v1/deploymentssays how many builds are kept (keptBuilds), and each endpoint what keeps its build (keptFor,keptForTotal). -
In the console:
- The console says correction, corrector group, test set, test run, suggested change, Improve run, pin and release gate, as the API now does, and the project's Quality page is Corrections.
- Agents, flows and runs have pages where they had rows of tabs. An agent's are Overview, Runs, Corrections, Test set, Suggested changes and Pinned versions, and its Overview says where each stands under How it gets better. A flow's are Overview, Runs and Corrections. A run's pages are under its agent or its flow, and an agent's Runs page has its turns in flows too; Menu > Runs still lists every run. The trail at the top ends on the page you're on, and its last crumb lists the other pages. Every page has its own link, and Copy copies the whole link. A run's id alone, as the CLI, the API and the logs give it, still opens its page.
- The release gate form sets how many cases must pass, that none that passed before fails, and a second person who approves. The comparison, evidence, figures, replay and only-experts rules are set with the API or the CLI: a gate saved from the form keeps them as they were, and lists them under Kept as they are.
- Schedule Improve opens from an agent's Suggested changes page, for that agent, and no longer from the Schedules page, which still lists every schedule.
- Links are underlined, and one that opens a new tab ends with an arrow. A section's buttons sit on the section they change, and only a page's main action is a filled button.
Known issues
Section titled “Known issues”- A release gate's
cases.noNewFailuresdoesn't count a case whose answer couldn't be checked, even if its decisions failed. Its message says how many cases it checked.
What the upgrade changes
Section titled “What the upgrade changes”- On Cloud Run with the module, the upgrade turns on Cloud Scheduler's
API, which starts the pack orchestrator. With
secrets_backend = "none", it also turns on Cloud KMS's and makes the module's key ring and key: each pack endpoint's token is now sealed under that key (KINDGI_PACK_ENDPOINT_KMS_KEY). With a private-IP database (database_private_network), turning on these APIs makes the plan show the server'sKINDGI_DATABASE_SERVER_CAas(known after apply): it's still the instance's CAs (Upgrade by hand).
Upgrade steps
Section titled “Upgrade steps”-
Eighteen new migrations: four new tables (
block_version_prs,env_cloud_secrets,run_filesandtool_file_tokens), new columns that are empty or have a fixed default, with nothing rewritten, and thesupervisor_fix_proposalstable dropped (below). The first start runs them, as it runs any other migration. They lock the tables they change or point to:agent_registry,agent_registry_versions,agent_promotions,block_registry_versions,deployments,deployment_endpoints,eval_runs,eval_suite_cases,improvement_proposals,judgments,orgsandprojects. Seven of the migrations hold the lock while they read every row, to check a new rule or build an index, and two of those tables can be large. The one that sorts corrections keepsjudgmentslocked while it indexes every judgment: meanwhile reading or saving judgments and corrections waits, on a server of the earlier version still running too. The one for test runs indexeseval_runs: meanwhile starting or updating a test run waits. With many of either (SELECT count(*) FROM judgments,SELECT count(*) FROM eval_runs), upgrade at a quiet time. A long transaction holding one of those tables makes the start stop after about a minute, naming the session that holds it. End that session or let it finish, then start again. On Cloud Run, the old revision serves meanwhile; on a single server, such as the Docker setup, the runtime is down until the new start succeeds. -
A
gcs:artifacts bucket: give the server's identitystorage.buckets.geton it before you upgrade. The upgraded runtime reads the bucket's settings at start, androles/storage.objectAdmindoesn't grant that permission, so without it the runtime refuses to start. Grantroles/storage.legacyBucketReaderon the bucket, or add the permission to a custom role. A ledger or purge-record bucket needs onlystorage.objects.create. -
With
KINDGI_ARTIFACTSset, give the server a core file limit of 0. Otherwise, on Linux, each start warns "Core files are on": a crash of the server's process would leave the files it holds in memory on disk, outside retention and the tenant purge.docker-compose.prod.ymlsetsulimits: core: 0; elsewhere, use--ulimit core=0withdocker run, orLimitCORE=0in a systemd unit. -
A site person's Ask gets the project's tools at their next sign-in. There's no migration. The first start brings each tenant's authorization store up to the new model, as at every upgrade, and logs
store <id> now has the current model. A store it couldn't update logscould not bring store <id> up to the current model(orcould not read its store's model to bring it up to date), and the next start tries again. A site person whose role may ask gets the newturn_invokerrelation at their next sign-in through the site. Until then, or while their tenant's store has the old model, their Ask's calls of the project's tools are refused, as before. The approval floor holds from the first start, though, so akindgi_rememberin their Ask waits for a yes from then on. A sign-in whose store refuses the write logs aWARN, once per tenant: "a site person's turn_invoker wasn't written". In the audit, a site person's tool call in their own turn logs twoauthz-decisionevents on the tool: theinvokedeny, as before, then the allow, whose evidence namesturn_invoker. -
Upgrading drops the old
supervisor_fix_proposalstable; at 0.3.x no route or job wrote to it. -
Projects gain a
sort_end_user_correctionscolumn, a yes or no. It's empty on existing projects, and empty reads as no: their end users' corrections aren't sorted, and an Improve schedule that takes everyone's corrections doesn't count them, until a project admin turns it on withsortEndUserCorrections: trueonPATCH /v1/projects/{projectId}(Where a correction goes). -
Right after the upgrade, a project no pin covers runs its Latest. That's whichever came last there: the version the newest deployment into the project shipped, or the newest version made in the project before 0.4.0, a derived one too, by when it was published. It's not always the highest version: the two differ after a deploy that rolled back, or a lower version published after a higher one. To keep a version running in a project, pin it there before you upgrade.
-
An Improve schedule saved at 0.3.x is read in 0.4.0's shape. Nothing rewrites it. Its
threshold.judgmentsis itscorrections, and the threshold'srunsandjudgesare dropped, so it fires on the count of corrections alone.budget.maxCostUsdis itsrunCapUsd,monthlyCapUsditsmonthCapUsd, andclassWeightsitsfrom(as-recordedreads aseveryone, andrestricted-onlyasexperts). Itsobjective,candidatesand the rest of itsbudgetare dropped. One saved for a segment improves the segment's whole project. One saved with noclassWeightsreads asexperts. At 0.3.x, where no expert group applied (none for the tenant, the project or the agent), it took everyone's corrections; now it takes only experts', so there it starts no Improve run. To keep everyone's, copy itsinputfromkindgi schedules get <schedule-id>, setfromtoeveryonein it, and send all of it back withkindgi schedules update <schedule-id> --input=@<file>. The update replaces the whole input: a field left out goes back to its default. The console can't change an existing schedule's input. -
Corrections made at 0.3.x go to nobody, so Improve doesn't learn from them until they're handed to it. A correction now says who fixes it: Improve, a developer or the agent's owner. An Improve run, or an Improve schedule, takes only an agent's open corrections handed to Improve. Upgrading keeps each older correction open, with nobody to fix it, and the console shows it as "Nobody yet" under Who fixes it. To have Improve learn from them, filter an agent's corrections by Who fixes it: Nobody yet, and hand each one to Improve with Hand it to someone else, or send
PATCH /v1/corrections/{id}with"sortedTo": "improve". Only an agent's corrections go to Improve: hand a flow's to a developer or the owner. -
An Improve run still going when you upgrade ends, and doesn't carry on. 0.4.0 checks a change case by case, and a run 0.3.x started didn't, so the run ends
failed: "An older version of the runtime started this Improve run, and this version can't carry it on. Start it again." One someone asked to stop endscancelled. The suggested change it made, and that change's check, stay for a person to look at. To lose no run, upgrade when none is going. -
Upgrade your clients, the CLI and your own callers with the runtime. 0.4.0 renames routes, fields, error codes and metric names, and keeps no old name:
/v1/gate-policiesis/v1/release-gates, andkindgi gate-policiesiskindgi release-gates, for one. A release gate saved at 0.3.x needs no step: the runtime reads its old names. Every renamed name is listed under Changed, or in the steps below. -
Console links saved before 0.4.0 can answer Page not found. Pages moved under the agent or flow they belong to, and 0.4.0 keeps no old address. Under
/tenants/<tenant>/projects/<project>/:- A run's tabs are under its agent or its flow:
agents/<agent>/runs/<run>/journal,/provenance,/costand/corrections, or the same underflows/<flow>/runs/<run>. A link toruns/<run>still opens the run, butruns/<run>/journal,/provenance,/costand/judgmentsdon't. - Quality is now Corrections:
corrections, andcorrectionson each agent and flow. A link toqualityanswers Page not found, whatever its tab. - Suggested changes are at
agents/<agent>/suggested-changes, which wasagents/<agent>/proposals, and an Improve run atagents/<agent>/improve-runs/<run>, which wasagents/<agent>/proposals/passes/<pass>. - A test run is at
test-runs/<run>, which waseval-runs/<run>. The project's Test sets pages are gone: each agent has its test set, atagents/<agent>/test-set. - A new release gate is made at
agents/<agent>/release-gates/new, which wasagents/<agent>/gate-policies/new.
- A run's tabs are under its agent or its flow:
-
A pack's copy of the
kindgi-usingskill gives 0.3.x console links until it's refreshed. A pack keeps the skill copies it was made with. Once its@kindgi/cliis upgraded,kindgi devrefreshes each copy you haven't edited as it starts, andkindgi skills syncrefreshes them any time (./kindgiw devand./kindgiw skills syncin a Java or Scala pack). A copy you edited is kept, andkindgi skills sync --forcereplaces it. Until then, an older copy gives a run's tabs asruns/<run>/costand the like, which 0.4.0 doesn't open, and names Quality where the console says Corrections. -
A webhook receiver, or code that reads approvals, sees 0.4.0's names. The Improve run's event is
improve-run.finished, which wasimprovement-pass.finished, and its data is indata.improveRun, which wasdata.pass. An endpoint subscribed to the old name gets the new one with no step; a new subscription must name the new one. An approval'ssubjectKindisagent-pin,factorsupervisor:suggested-change, which wereagent-promotion,memory-factandsupervisor:fix-proposal. The API takes only the new names; approvals stored before read with them. -
A stdio MCP server that keeps a credential in
config.envstill works, and the runtime says so at each start: move it intosecretEnv. For each stdio endpoint registered with a credential in plaintextconfig.env, or with asecretRef, which a stdio server is never sent, the boot logs aWARNundermcp.envthat names the endpoint and thesecretEnvthat replaces it;kindgi-runtime check mcp-env-credentials, andkindgi doctor'smcp-envcheck, list the same. Itsconfig.envvalues now read back as"[redacted]", and registering one again with a credential inconfig.envis refused. To move one, store eachconfig.envvalue as a secret (asecretRefis stored already), then unregister the endpoint and register it again withsecretEnv(MCP servers). An HTTP MCP endpoint withsecretEnvin the config file stops the boot: only a stdio server is given one. -
The expert queue's records are logged under
expert-queue, which wasjudging. InKINDGI_LOG_LEVELS, changejudging=<level>toexpert-queue=<level>. The old name only warns at boot, as a name no subsystem logs under, and has no effect. -
On Cloud Run with the module, the upgrade moves the packs to the module's pack orchestrator. With the one pack service, from the apply until each pack is deployed again, calls to a deployed pack's tools are refused (
pack-route-missing, then, for about a minute,pack-endpoint-pending), so upgrade at a quiet hour. Withtenancy = "multi", stop your own orchestrator first: the services it made keep serving, while their hosts match*-<project number>.<region>.run.app, until each tenant deploys its packs again. The module'supgrade.shmakes the switch in one apply, and then prints the steps that finish it: mint the orchestrator's key, apply again withpack_image,pack_min_instances,pack_envandpack_secret_envout of the var files, set the pack's env in Kindgi, and deploy each pack again with a new idempotency key (From the one pack service). -
On Cloud Run, a pack's first call after a quiet spell waits for an instance to start. The one pack service of 0.3.x kept
pack_min_instancesinstances running, 1 by default, so a first tool call didn't wait for one. Each deployment's own service keeps none: it scales to zero when it's idle. The Cloud Run module no longer takespack_min_instances:upgrade.sh's steps take it out of the var files, and in amoduleblock that calls the module it's an error now, aspack_image,pack_envandpack_secret_envare.