Skip to content

Kindgi 0.4.0

View as Markdown

Released November 3, 2026. For the docs of this version, see docs.kindgi.com/v0.4.0.

  • 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 shows waiting-on-run, with waitingOn naming 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 the tenants and erasures commands' --record, --from, --ledger and --out, take s3:<bucket>[/<prefix>], on AWS S3 or a store that speaks S3, such as MinIO or R2. KINDGI_S3_REGION names the buckets' region. On AWS the runtime signs in as its AWS identity (KINDGI_AWS_IDENTITY); a compatible store takes KINDGI_S3_ENDPOINT, KINDGI_S3_PATH_STYLE and its own key in KINDGI_S3_CREDENTIALS_PATH. A delete removes every version of a file and its unfinished uploads. The runtime checks a KINDGI_ARTIFACTS bucket on s3: 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 honors If-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 type yes at 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-run lists what a real run would change. Use it as of the @kindgi/sdk@0.4.0 tag. The module's new database_url_version pins the version of the database-url secret the server reads: the way back sets it, and upgrade.sh refuses to start while it's set (Azure Container Apps).

  • Retired blocks, policies and release gates can be found. GET /v1/blocks, /v1/policies and /v1/release-gates take ?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, with unregisteredAt, so you can reinstate a version. In the TypeScript client, blocks.list, policies.list and releaseGates.list take includeRetired, and in the Python client include_retired. In the CLI, kindgi blocks list and kindgi release-gates list take --include-retired. kindgi exports create now 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 a FileValue), and the model call sends them inline: JPEG, PNG and WebP images (5 MB each) and PDFs (10 MB) to a model that declares vision, 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 a file-refused warning. GET /v1/conversations/{conversationId}/messages answers each message's files. Files need KINDGI_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 as bad-input, naming it. KINDGI_FILE_MEMORY_MIB sets 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), and KINDGI_FILE_CACHE_MIB how 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: true gets ctx.files.store({ name, contentType, bytes }), and one that declares readsFiles: true gets ctx.files.read(artifactId). Only a tool with a handler can declare them. In a pack (protocol 2.10.0), they go through POST /v1/tool-files and GET /v1/tool-files/{artifactId}, with the call's own token. The mail tools gmailAttachmentGet and outlookAttachmentGet store 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 with POST .../test-set/cases, and retire one with .../test-set/cases/{caseId}/retire. A test run of agent.<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. passRate counts those parts, so a test set of cases that expect only an answer has a passRate where it had null. A comparison says in unchecked why 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 fixed in that version, or reopened, with reopenedIn ({ 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 a cases rule: minPassing, and noNewFailures, which refuses a version that fails a case that passed before (Release an agent version).

  • An agent has an owner. PUT /v1/agents/{agentId}/owner with { "userId": "..." } (client.agents.setOwner), with admin on the agent, names the person who owns it, and GET /v1/agents/{agentId} answers owner: { 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 with format=jsonl, and the audit log records each export. client.corrections.export and kindgi corrections export --agent=<agent-id> give it, and --out=<file> writes it to a file. client.corrections.thumbs records an end user's thumbs up or down from your app's server, as a correction of the run's answer; a thumbs down needs why. A suggested change says how many corrections it fixes in correctionCount (Record your users' thumbs).

  • A reviewer can approve a fact with their own text. POST /v1/approvals/{approvalId}/complete takes factText, with decision: approve on a fact approval only (any other answers 400 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 as decision.factText, and approvals.decide takes it. The remember tool 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, and source: api, deploy with the deployment's id, or suggested-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 pull writes 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, sends source: the origin remote as host/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 pull brings the version into your files instead. None is opened under kindgi 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}/pin pins 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 answers 409 suggested-change-out-of-date and 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 with rebuilding: 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 (with gh), and marks the corrections it fixes that are still open as being-fixed. Both pull commands refuse a block file that holds edits the runtime doesn't have, naming it, and write nothing (Suggest a change, and test it).

  • kindgi flows and kindgi tools pin versions. Each has pinned, pinned-versions, pin, unpin and pin-history list, as kindgi agents has, 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 answers 409 pin-superseded, which was promotion-superseded. An unpin is still refused. Before a pin writes, kindgi agents pin and kindgi suggested-changes pin say which files git hasn't committed (uncommittedFiles and notInGit on 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. The returns-helper template's README walks the loop end to end.

  • Calendar tools. @kindgi/connections/google/tools has googleCalendarEventsList, googleCalendarFreeBusy, googleCalendarEventCreate and googleCalendarEventUpdate, and @kindgi/connections/microsoft/tools has the four outlookCalendar* 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.com opens the store's WordPress Authorize Application page (WordPress 7.0 or later). Once one of its administrators approves, it makes the kindgi-agent user a Shop Manager and saves WOO_STORE_URL, WOO_USER and WOO_APP_PASSWORD in 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. The kindgi-fix-corrections skill 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 at KINDGI_PACK_CALL_TIMEOUT_MS.

  • The pack orchestrator's routes and settings. kindgi-runtime packs orchestrate runs one pass of the pack orchestrator and exits, for a Cloud Run Job once a minute, with a system key that has system:deployments and system:pack-env. It reads KINDGI_ORCHESTRATOR_RUNTIME_URL, KINDGI_ORCHESTRATOR_SYSTEM_KEY, KINDGI_ORCHESTRATOR_PROJECT, KINDGI_ORCHESTRATOR_REGION, KINDGI_ORCHESTRATOR_PACK_SERVICE_ACCOUNT and KINDGI_ORCHESTRATOR_PACK_SERVICE, and gives each pack service KINDGI_PACK_SERVICE_MAX_CONCURRENCY, its concurrency. For a runtime behind Cloud Run IAM, KINDGI_ORCHESTRATOR_RUNTIME_AUTH=google-id-token adds 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 last problem. A new code, pack-env-name-too-long, there or on a ready one's packEnvProblem, 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 subsystems pack-orchestrator and block-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-deployment needed KINDGI_TENANCY=multi and KINDGI_SECRETS_BACKEND=postgres. A one-tenant runtime now takes it too, with KINDGI_PACK_ENDPOINT_HOSTS naming the hosts a deployment's endpoint may be on, and each endpoint's token can be sealed under KINDGI_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 needs KINDGI_PACK_ROUTING=per-deployment; off, the default, its routes answer 501 cloud-secrets-unsupported), a system key with system:env-refs sets a name to projects/<project>/secrets/<secret>/versions/<number>, as kindgi 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, and kindgi env list prints NAME (cloud secret).

  • kindgi deploy --hosted says how many builds are kept, and kindgi deployments get what 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 deploy prints Builds kept in this project: N (workspace, when the deploy names no project), and kindgi deployments get lists what keeps the build under Kept for: (endpoint.keptFor, and keptBuilds on GET /v1/deployments). kindgi deployments says why a superseded one was taken down (Deploy your agent to Kindgi Cloud).

  • Every union in openapi.json maps its tags. Nine unions, among them AgentPinScope, PinScope, ImproveRunOutcome and MCPEndpointAuth, now have a discriminator.mapping, so a client generated from it types each tag as the value the server sends, such as suggested. 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.zip from 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 every kindgi_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 sets separateApprover. 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/artifacts belongs to the server's user (uid 10001), so a Docker named volume mounted there takes that owner, for KINDGI_ARTIFACTS=local:/var/lib/kindgi/artifacts. Each local: 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_HOST works 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 write on 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, upload kindgi-0.2.0.zip from 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 takes run.finished got 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/pin and .../pinned/check refuse a testRunId whose run didn't complete (400 bad-input).
  • OpenAI-compatible providers send a model's registered maxOutputTokens when 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. The openai, groq and openrouter presets 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 on PATH. A git, or an sh, bwrap, mktemp, sed or rm, in the pack's folder no longer runs in their place. When one isn't on PATH, kindgi dev stops with spawn <name> ENOENT.
  • kindgi deploy says when nothing new was deployed. When the server answers from its record of an earlier request with the same Idempotency-Key, it says nothing new was deployed, where it printed "Deploy complete." under its replay note. Its JSON adds idempotentReplay: 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 plain az acr login, as the module's upgrade.sh does (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 marked resultIsOutsideData has its results treated as outside data again. kindgi dev dropped 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.
  • 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}/promotions and client.deployments.promote.

  • A judgment is now a correction.

    • /v1/judgments is /v1/corrections, and /v1/judgments/{judgmentId}/unregister is /v1/corrections/{correctionId}/remove. The retention domain judgment is correction (POST /v1/retention/sweep/correction).
    • judgmentId and judgmentIds are correctionId and correctionIds. judgmentCount, runsWithJudgments and anyJudgment are correctionCount, runsWithCorrections and anyCorrection. An answer's judgments is corrections, a comparison summary's corrections.judgments is corrections.results, a comparison case's judgedItems is correctedItems, and a changes.new entry's judged is corrected.
    • The error code judgment-not-found is correction-not-found.
    • Judgment and JudgmentWithCopies are Correction and CorrectionWithCopies. The { calls, notCalled } value that was called Correction is ExpectedDecisions, graded as ExpectedDecisionsResult. Judged* names are Corrected*, and UnregisterJudgmentResult is RemoveCorrectionResult.
    • client.judgments is client.corrections, and its unregister is remove. kindgi judgments add|list|show|unregister is kindgi 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-classes is /v1/corrector-groups, with {correctorGroupId} in its paths. /v1/projects/{projectId}/judging-queue is /v1/projects/{projectId}/expert-queue, and /v1/projects/{projectId}/judging-rules is /v1/projects/{projectId}/queue-rules, with the same paths below them. The retention domain judge_class is corrector_group.
    • judgeClassId is correctorGroupId. A correction, a corrected item and a test case's item say expert where they said restricted. classWeights is groupWeights, and its value restricted-only is experts-only. A release gate's onlyRestrictedClasses is onlyExpertGroups, and its check is named groupWeights.expertsOnly. The expert queue's state judged is corrected, as is a rule result's judged count; progress byClass is byGroup, and wantedClassIds is wantedGroupIds.
    • Error codes starting judge-class- start corrector-group-, codes starting judging-rule- start queue-rule-, and the other judging- codes start expert-queue-.
    • JudgeClass* names are CorrectorGroup*, JudgingRule* names are QueueRule*, and the judging queue's Judging* names are ExpertQueue*. In the Python client, Restricted is Expert.
    • client.judgeClasses is client.correctorGroups, client.projects.judgingQueue is client.projects.expertQueue, and client.projects.judgingRules is client.projects.queueRules.
    • kindgi judge-classes is kindgi corrector-groups, kindgi judging-queue is kindgi expert-queue, and kindgi judging-rules is kindgi queue-rules. --class is --group, --clear-class is --clear-group, and --class-weights is --group-weights.
  • Eval suites are now test sets.

    • /v1/eval-suites is /v1/test-sets, with {testSetId} in its paths and the same paths below it, runs too.
    • suiteId is testSetId wherever it names a test set, and suiteVersion is testSetVersion. A test set's and a test run's kind judged is corrections. A release gate's comparison.suite is comparison.testSet, and so is its check's name; a comparison's summary says testSet where it said suite. The retention domain and the authorization resource type eval_suite are test_set. A reference-out-of-scope issue names a test set with the kind test-set, where it said suite.
    • Error codes starting eval-suite- start test-set-.
    • EvalSuite* names are TestSet*, EvalKind is TestSetKind, EVAL_KINDS is TEST_SET_KINDS, and JudgedEvalCase, JudgedEvalCaseCollectionPage and JudgedEvalCaseCorrection are CorrectedTestCase, CorrectedTestCaseCollectionPage and CorrectedTestCaseCorrection.
    • The test set file's schema is @kindgi/specs/test-set.schema.json (was eval-suite.schema.json). A file whose $schema names https://kindgi.com/schemas/v1/eval-suite.schema.json needs https://kindgi.com/schemas/v1/test-set.schema.json. Its kind takes corrections, as the API does, and its reference page is Test set.
    • client.evalSuites is client.testSets. kindgi eval-suites is kindgi test-sets, --suite is --test-set, and --suite-version is --test-set-version. kindgi exports create writes them as test-sets and test-set-versions.
  • Eval runs are now test runs.

    • /v1/eval-runs is /v1/test-runs, with {testRunId} in its paths; cancel, events and rescore keep their paths. POST /v1/test-sets/{testSetId}/runs still starts one.
    • A test run's own id is testRunId where it was runId: in the start and rescore answers, the run view and the list rows. Ids of agent runs, such as a case's runIds, keep their names. evalRunId is testRunId wherever 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/runs filter.
    • The stream's events eval-run.completed, eval-run.failed, eval-run.cancelled, eval-run.case-completed and eval-run.case-failed are test-run.*, with the same endings. The compliance evidence kind eval-run is test-run, and GET /v1/compliance/evidence?kind= answers 400 for a kind that is neither built in nor named by the classifier, such as eval-run, where it answered an empty page.
    • Error codes starting eval-run- start test-run-.
    • EvalRun* names are TestRun*. EvalComparison, EvalBaseline, EvalOverrides, EvalSample, EvalReads and EvalClassWeights are TestRunComparison, TestRunBaseline, TestRunOverrides, TestRunSample, TestRunReads and TestRunGroupWeights.
    • client.evalRuns is client.testRuns. kindgi eval-runs is kindgi test-runs, and --eval-run is --test-run, on kindgi agents pin and kindgi runs list. kindgi exports create writes them as test-runs.
  • Choosing what a project runs is a pin, for agents as for flows and tools.

    • An agent's /promotions is /pinned/pin, /promotions/check is /pinned/check, its list of promotions and /promotions/{promotionId} are /pin-history and /pin-history/{changeId}, /live is /pinned, /live-versions is /pinned-versions, and /live/unpin is /pinned/unpin. /live/rollback is removed: going back is a pin of an earlier version, through the same release gate and approval.
    • promotionId is changeId: on a pinned version, in a deployment's pin gate and in a refused pin's details. A pin's status promoted is pinned, and the check's outcome would-promote is would-pin; a pin's action is pin or unpin.
    • What an agent resolves to: via: 'live' is 'pinned', and liveScope is pinnedScope. So are a run's via and a queue rule's when.versions value; a when.versions entry that is neither an exact version, such as 1.2.0, nor pinned is refused (400). A test run comparison's baseline { live: ... } is { pinned: ... }, a compared version's via value live is pinned, and the CLI's --baseline live is --baseline pinned.
    • Unregistering a pinned agent version answers agent-version-pinned (was agent-version-live), as for flows and tools, and lists the scopes it's pinned in under pinned (was live). The permission promote on an agent is pin. The audit kinds agent-promotion, agent-promotion-refused, agent-live-unpinned and agent-live-pin-inactive are agent-pinned, agent-pin-refused, agent-unpinned and agent-pin-inactive, and agent-rollback is gone.
    • promotion-not-found, promotion-superseded and promotion-gate-unsupported are pin-not-found, pin-superseded and pin-gate-unsupported, and live-scope-spans-environments is pin-scope-spans-environments, the code a flow or tool pin answers. nothing-to-roll-back is gone with the rollback route. Environment promotion's codes keep their names.
    • Promotion, PromotionPage and PromotionCheck are Pin, PinPage and PinCheck. PromoteBody and UnpinBody are AgentPinBody and AgentUnpinBody. LivePin, LivePinList and LiveVersionResolution are AgentPinnedVersion, AgentPinnedVersionList and AgentPinnedVersionResolution. An agent's pin scope is AgentPinScope, made of the PinScope* schemas flows and tools use, with PinScopeSegment for a segment. In @kindgi/types, LiveScope is AgentPinScope. In the Python client, LiveScopeOrg, LiveScopeProject, LiveScopeSegment and LiveScopeTenant are PinScopeOrg, PinScopeProject, PinScopeSegment and PinScopeTenant, and LiveScopeUnrecognized is AgentPinScopeUnrecognized.
    • client.agents.pinned has resolve, list, pin, check, unpin, history and getChange; client.agents.promotions and client.agents.live are removed. Its types are AgentPinnedClient, AgentPinnedWhere, AgentUnpinInput and ListPinHistoryFilter.
    • kindgi agents promote is kindgi agents pin, promotions list|get is pin-history list|get, live is pinned, and live-versions is pinned-versions. kindgi agents rollback is removed. <promotion-id> is <change-id>.
  • A deployment promotion's make-live is now a pin. A promotion's makeLive is pin: 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 under pinned (was live), beside pinnedFlows. A write error after some were pinned lists them in error.details.pinned (was error.details.live) and error.details.pinnedFlows. DeploymentLivePin and DeploymentLivePinGate are DeploymentPinnedAgent and DeploymentPinGate. kindgi promote --make-live is kindgi promote --pin, and --wait goes with --pin; its output lists the carried agents' pins under Agent pins in <env>: (was Live in <env>:). kindgi dev's line for a block version pinned in the console says pinned: (was made live:).

  • Improvement passes are now Improve runs.

    • /v1/improvement-passes is /v1/improve-runs, with {improveRunId} in its paths, and cancel keeps its path. POST /v1/proposals/improve is POST /v1/improve-runs, and POST /v1/proposals/improve/estimate is POST /v1/improve-runs/check.
    • passId is improveRunId wherever it names an Improve run: on a schedule's fire and on a suggested change's madeBy. A suggested change's drafter is madeBy and its hypothesis is why, in the body that creates one and in an Improve run's comparisons too. An Improve run's outcome proposed is suggested. A test run's passCount keeps its name: it counts the cases that passed.
    • improvement-pass-not-found and improvement-pass-finished are improve-run-not-found and improve-run-finished.
    • ImprovementPass* names are ImproveRun*. The start body is StartImproveRunBody (was ImproveBody), for a start and a check, and the check's answer is ImproveRunCheck (was ImprovementPassEstimate). SuggestedChangeDrafter is SuggestedChangeMadeBy.
    • client.improveRuns has start, check, list, get and cancel; client.improvementPasses and client.proposals are removed. Their inputs are StartImproveRunInput and CheckImproveRunInput, and @kindgi/sdk exports ImproveRunsClient where it exported ProposalsClient.
    • kindgi improve runs start starts one (was kindgi proposals improve), and kindgi improve runs list, get and cancel replace kindgi proposals passes; kindgi proposals is removed. <pass-id> is <improve-run-id>. kindgi exports create writes them as improve-runs.
  • Proposals are now suggested changes.

    • /v1/proposals is /v1/suggested-changes, with {suggestedChangeId} in its paths. .../request is .../pin. .../rollback is removed: going back is pinning the agent's earlier version.
    • proposalId is suggestedChangeId wherever it names a suggested change: on a version's derivedFrom, on an Improve outcome, and in a refused gate's details. A suggested change's status promoted is pinned. The header X-Proposal-Deduped is X-Suggested-Change-Deduped.
    • Error codes starting proposal- start suggested-change-.
    • Proposal* and FixProposal* names that stay are SuggestedChange*, and FixProposalId is SuggestedChangeId. A suggested change rolled back by the removed route reads as pinned.
    • client.suggestedChanges holds suggested changes, and its request is pin. Its rollback is removed: pin the agent's earlier version with client.agents.pinned.pin. kindgi proposals commands are kindgi suggested-changes, whose verbs change too (below), and rollback is removed: kindgi agents pin with the earlier version puts it back. kindgi exports create writes them as suggested-changes.
  • A gate policy is now a release gate.

    • /v1/gate-policies is /v1/release-gates, with the same paths below it, and an agent's /gate-policy is /release-gate. The operation ids gatePolicies.* and agents.gatePolicy.resolve are releaseGates.* and agents.releaseGate.resolve, under the tag release-gates.
    • A release gate's policyId is releaseGateId. The release gate a pin names is releaseGate (was policy): on a pin and in the pin history, in a pin check's answer, in a refused pin's details, in a pin-gate-unsupported answer, in a deployment promotion's pin gate, and in the answer of GET /v1/agents/{agentId}/release-gate.
    • A test run comparison's weightedYesShare is passRate, and its judgedCoverage is caseCoverage. So are the metric names in a release gate's spec, and the objective of an Improve run, a schedule's Improve run and the Improve run webhook event (passRate, the default, or weightedPrecisionAtK); the CLI's --objective takes the same values. The gate's check baselineIsLive is baselineIsPinned.
    • gate-policy-not-found, gate-policy-already-registered, gate-policy-scope-taken, gate-policy-scope-changed, gate-policy-scope-unpinned, gate-policy-needs-pin and gate-policy-descendant-unpinned are release-gate-not-found, release-gate-already-registered, release-gate-scope-taken, release-gate-scope-changed, release-gate-scope-unpinned, release-gate-needs-pin and release-gate-descendant-unpinned, with the same statuses and bodies.
    • A spec's approvals.forRollback is 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, GatePolicySpec and PublishGatePolicyBody are ReleaseGate, ReleaseGatePage, ReleaseGateRef, ReleaseGateResolution, ReleaseGateSpec and PublishReleaseGateBody.
    • client.gatePolicies is client.releaseGates, and client.agents.gatePolicy is client.agents.releaseGate, with the types ReleaseGatesClient, ReleaseGateVersionsClient, AgentReleaseGateClient, ReleaseGateFilter and PublishReleaseGateInput.
    • kindgi gate-policies is kindgi release-gates, kindgi agents gate-policy is kindgi agents release-gate, <policy-id> is <release-gate-id>, and --policy-version is --release-gate-version. In an export, the kinds gate-policies and gate-policy-versions are release-gates and release-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 under guides/improve/, so old links to them don't open. Four have new names: judge-a-runs-output is correct-a-runs-output, propose-a-change is suggest-a-change, judging-reference is expert-queue-reference, and live-versions-reference is pinned-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: agentReleases is agentPins, judgmentRegistry is correctionRegistry, evalSuiteRegistry is testSetRegistry, evalRunBinding is testRunBinding, judgingQueue is expertQueue, improvementPasses is improveRuns, and evalCaseStore is frozenCaseStore. 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, blockVersionPullRequests and envCloudSecrets. Each one's type says what happens without it. For example, without testSetFreeze, making or checking a suggested change answers 501 suggested-change-check-unsupported, and without envCloudSecrets the cloud secrets routes answer 501 cloud-secrets-unsupported.
    • Pins: implement AgentPinnedVersionBinding (was LiveVersionBinding) and PinBinding (was PromotionBinding), with AgentPinBindings and AgentPinGateDeps (were AgentReleaseBindings and AgentReleaseGateDeps). AgentPinBindings holds them as pinned and changes (were live and promotions). Their types are Pin, PinStatus, PinAction, PinError, PinErrorCode, PinRequestInput, ListPinHistoryInput, AgentPinInput, AgentUnpinInput, AgentPinnedVersion, AgentPinResolution and AgentPinResolveInput; PromotionActor and PinActor are one PinActor, and liveScopeCoordinates is agentPinScopeCoordinates. rollback and RollbackInput are gone, and an unregister a pin refuses answers pinned (was live). A run's liveScope is pinnedScope in @kindgi/runtime and @kindgi/agents.
    • Release gates: implement ReleaseGateBinding (was GatePolicyBinding) as AgentPinBindings' releaseGates (was gatePolicies), with ReleaseGateError, ReleaseGateErrorCode, ReleaseGateListInput, ReleaseGatePublishInput and ReleaseGateVersionInput.
    • Latest: AgentPinBindings.latest, a LatestBinding, is required, and so are AgentPublishInput.madeFor and AgentRegistryBinding.markLatest. whatRuns and whatRunsByProject answer a scope's pin, else its Latest.
    • Test runs and test sets: EvalSubjectInvoker is TestRunSubjectInvoker, and EvalCaseStoreBinding, EvalCasePutInput, EvalCaseListInput and EvalCasePage are FrozenCaseStoreBinding, FrozenCasePutInput, FrozenCaseListInput and FrozenCasePage.
    • Corrections: CorrectionRegistryBinding gains update, counts, correctionsByIds and applyRunOutcome, and the test set's testSet, listCases, getCase, runCopies, addCase and retireCase, all required. Its class methods are group methods: createGroup, listGroups, getGroup, updateGroup and unregisterGroup. It loses listJudgedRuns, and its unregister sets the status to removed. sortAtSave and planChange are exported, so every store sorts and changes a correction by the same rules.
    • Suggested changes: SupervisorBinding's listProposals, getProposal, createProposal and recordProposal are listSuggestedChanges, getSuggestedChange, createSuggestedChange and recordSuggestedChange.
    • Pack services: SystemDeploymentsBinding.listReady is new and required. It answers GET /v1/system/deployments?endpoint=ready (client.systemDeployments.list('ready')): the deployments whose endpoint is ready and whose pack service stays, across tenants, oldest first, with the same paging as endpoint=missing and endpoint=retire.
    • @kindgi/tools: latestVersion is highestVersion, 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/corrections takes decisions and answer, each right or wrong, and items, at least one of the three. Wrong decisions need shouldCall ([{ tool, args? }], with args only when the inputs matter) or mustNotCall (tool ids). A wrong answer needs shouldSay or why. items ([{ key, pointer?, rank?, verdict }]) is for an answer that is a ranked list. item, verdict, reason and correction are 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 same participantId, 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 is fixed, as recorded-right. An app end user's correction (one with a participantId, and not an expert's) stays open and unsorted, unless a project admin sets sortEndUserCorrections: true on PATCH /v1/projects/{projectId}. A correction answers status, sortedTo, sorted, link, fixedIn, statusNote and updatedAt. PATCH /v1/corrections/{correctionId} (client.corrections.change) sorts it again, changes its status, or both: it needs publish on the agent, or, for an agent more than one project serves, write on the correction's project. A change its status doesn't allow answers 409 correction-status-change-not-allowed, with details: { from, to }. Removing a correction, by its author or an admin of its project, makes it removed. GET /v1/corrections filters by status (not-fixed for open, being-fixed and with-owner), sortedTo (none for the unsorted), from (experts, end-users or all), madeBy=me, since and until, and verdict is gone. GET /v1/corrections/counts (client.corrections.counts) counts a project's corrections, or one agent's, by status.

  • kindgi corrections takes a correction's parts as the API names them. kindgi corrections add takes --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 --yes or --no as before. --correction, --reason and --item=answer are gone. Each call still adds to your correction of the run: a part it gives replaces what you said about that part. The new kindgi corrections set <correction-id> takes --sorted-to=improve|developer|owner, --status=open|being-fixed|wont-fix, --link for what fixes it, and --reason, which wont-fix needs. kindgi corrections list loses --verdict, and takes --status, --sorted-to, --from=experts|end-users|all and --since=<time>. It lists removed corrections only when --status names removed.

  • client.supervisor is gone from the TypeScript client. Every method on it threw not-yet-wired: use client.suggestedChanges and client.observations. With it go SupervisorClient, SupervisorProposalsClient and their input types, SupervisorSpec, Supervisor, DryRunCriterion, and the proposal result types no method returned. The error code supervisor-header-missing, which the API never sent, leaves the API's codes and the TypeScript, Python and Java clients.

  • The TypeScript client's client.observations keeps only query. recordRun and patterns, which threw not-yet-wired, are gone, with PatternsInput.

  • The TypeScript client's list pages drop items. A list call answers the API's page alone: data, hasMore and nextCursor. items was deprecated before and is gone now: read page.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, and GET /v1/agents/{agentId} still answers it. GET /v1/agents/{agentId}/projects says, 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: pin or latest), the pins on segments inside it (segments), and the agent's highest version. What serves a scope, a pin's check, a flow publish's default agent pin and a trigger's toolsAllowedUnattended check 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, or 409 project-suspended when the project is suspended, since there's nothing to measure it against. It was measured against the highest version. The TypeScript client throws ConflictError for it.

  • A trigger's toolsAllowedUnattended is 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 answers 400 bad-input when 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. Name agentVersion, 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 answers 201. POST /v1/agents/{agentId}/pinned/pin answers the pin change under pin, the test runs that check it, and the corrections a reused test run changed (PinAnswer), still with 201, or 202 while it waits for an approval. POST /v1/agents/{agentId}/pinned/unpin answers the same shape with 201, where it answered 200 with the change alone. POST /v1/suggested-changes/{suggestedChangeId}/pin answers the same shape, with the suggested change under suggestedChange (SuggestedChangePinAnswer). agents.pinned.pin, agents.pinned.unpin, suggestedChanges.pin, kindgi agents pin, kindgi agents unpin and kindgi suggested-changes pin give 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 in details.projects. Nothing is recorded. Send stopFollowingLatest: true to pin anyway, or --stop-following-latest on kindgi agents pin and kindgi suggested-changes pin; the change then records stoppedFollowingLatest: true. Such a pin went through before. A deployment promotion's pin is never refused this way.

  • Kindgi names its own test runs, so a start can't. POST /v1/test-sets/{testSetId}/runs refuses a correlationId that starts with pin: or latest: (400 bad-input): those name the test runs a pin or Latest moving starts.

  • A suggested change's fixes are checked when it's made. Each id must be a correction in the suggested change's own project: POST /v1/suggested-changes refuses an unknown id, or another project's, with 400 validation-failed, listing them in details.fixes, and makes nothing. fixes names 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-runs takes { agentId, projectId, tiers?, model?, candidates?, budget?, objective?, groupWeights? }. projectId is required, and a body that sends scope, testSetId or fromVersion is 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-runs takes projectId and status (Improve an agent).

  • An Improve run checks it's ready before it starts. POST /v1/improve-runs/check answers { ready, startsFrom, items, estimate, month }: items lists what's missing, from wording, settings, test-cases, permission, one-at-a-time and project, each with its fix. The check's estimatedCostUsd, maxCostUsd and basis move under estimate ({ costUsd, maxCostUsd, basis }), and month is this month's spend against the Improve schedule's cap. A start that isn't ready answers 409 improve-not-ready, with the missing items in details.items, and a second start for the same agent and project answers 409 improve-run-running, with details.improveRunId. A start no longer answers validation-failed for no-tunable-keys or no-pinned-prompt-block, and proposal-needs-pin is gone.

  • An Improve run's record changes. candidatesEvaluated is tried. It gains projectId, startsFrom ({ version, follows }), testSetVersion, setAside ({ cases, of }) and takes, the correction ids it took, and loses fromVersion, scope and testSetId; groupWeights is always there. Its outcome is suggested, nothing-better (was nothing-found, with reason and an optional holdOut), cost-cap (new, with spentUsd) or failed. A comparison's part can be all, for the proof. The improve-run.finished webhook 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, with details.scheduleId and details.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 (monthCapUsd was monthlyCapUsd). threshold, candidates, budget, objective and groupWeights are gone, and an option it doesn't have is refused. A schedule at its month's cap stays active and says until when (pausedUntil, with pausedReason: 'month-cap'). One whose owner loses publish on 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 takes write on the project and publish on the agent; an admin of its project may also pause or unregister one without publish.

  • The TypeScript client and the CLI follow. StartImproveRunInput and CheckImproveRunInput take projectId (required), tiers, objective, groupWeights, model, candidates and budget, and ImproveRunsListInput takes projectId and status. A 409 improve-not-ready is a conflict whose fields.items lists what's missing. kindgi improve runs start takes --project (required) and --check, which prints the readiness items, the estimate and the month, starts nothing, and exits 3 when it isn't ready; --tier repeats. --tenant, --org, --segment, --pass-project, --test-set and --from-version are gone. kindgi improve runs list takes --project and --status. kindgi schedules create --improve needs --project, and its --segment is 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. Its kind comes from the status and the provider's words (invalid-request, auth, rate-limited, unavailable, context-too-long or content-filter, and network for Anthropic's failed connection), with its status, and its message is the same as before. The provider SDK's own error (Anthropic's APIError, Gemini's ApiError) is now its cause: code that checked the thrown error's type checks cause instead. 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.env is refused. Give a stdio endpoint its secret variables in secretEnv, 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 in config.env, such as GITHUB_TOKEN, OPENAI_API_KEY or DB_PASSWORD, is refused (invalid-mcp-endpoint, reason credential-in-env), naming the variable and the secretEnv that replaces it; a lone KEY, as in CACHE_KEY, doesn't count. secretRef on a stdio endpoint is refused too (secret-ref-on-stdio), since a stdio server gets no headers, and secretEnv on an HTTP endpoint (secret-env-on-http). Every config.env value reads back as "[redacted]", its name kept, on endpoints registered before too, so an export holds the names and not the values. A config.env value of exactly "[redacted]" is refused (invalid-stdio-env), so registering an endpoint again from what its GET answers fails until its values are put back, or its secrets move to secretEnv. A value with a NUL, and a name that's empty or holds = or a NUL, are refused too. Endpoints registered before keep working, and kindgi doctor's new check mcp-env lists each stdio endpoint that keeps a credential in config.env, or a secretRef, with the fix. If you go back to an earlier runtime, an endpoint registered with secretEnv starts without those variables (MCP servers).

  • A provider registration with a field it doesn't take is refused. POST /v1/providers answers 400 invalid-provider, with reason unknown-model-field or unknown-metadata-field, naming the field and the fields a model takes. Before, such a field was dropped without a word, so a misspelled thinking registered 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-changes takes agentId, projectId, block, and values for a settings block or template for a prompt block, with why and fixes (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 .../check checks it again, in place of evaluate and rescore, which are gone. fromVersion, scope, tier, change and evidence are gone from the body and the answer, and candidate, evaluation, promotion and rolledBack from the answer. The list takes agentId, projectId, status and madeBy, not tier or a scope. Its status is checking, check-failed, ready, waiting-for-second-person, pinned, added-as-latest or withdrawn. 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, create takes the new body, check replaces evaluate and rescore, and ProposalTier and EvaluateProposalInput are gone from it. kindgi suggested-changes create replaces draft: it needs --project and takes --why and --fixes, once per correction, and --from-version, --tenant, --org, --segment and --tier are gone. check replaces evaluate (Suggest a change, and test it).

  • Deriving an agent version through the API is gone. POST /v1/agents/{agentId}/versions is removed, with client.agents.versions.derive, DeriveAgentVersionInput and kindgi agents derive. A suggested change makes such a version now, and checks it. A version derived before keeps its derivedFrom.

  • 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_judgments in the Python client) and kindgi eval-suites from-judgments are removed, and so is the error code test-sets-not-supported. A corrections test set built before still reads by its id, but GET /v1/test-sets and kindgi test-sets list list one only with kind=corrections. A test set id that starts with agent. is kept for an agent's own test set: POST /v1/test-sets refuses 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's runId is required.

  • A block an agent version uses for its model settings takes model settings only. POST /v1/blocks refuses 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/deployments compares 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 answers 409 deploy-would-put-back-older-blocks, lists each block in details.blocks, and writes nothing. To put one back on purpose, name it in the body's replace ([{ blockId, reason }]), or run kindgi deploy --replace=<block> --reason=<text>. POST /v1/deployments/check (client.deployments.check) answers the same with nothing written, and kindgi deploy asks it before it builds an image. A deployment promotion with pin runs the same check against the target project, and kindgi promote --pin takes --replace too.

  • The Cloud Run module's one-pack-service variables are gone. pack_image, pack_min_instances, pack_env and pack_secret_env, and the output pack_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_prefix can't be kp or start with kp-. pack_concurrency and pack_max_instances take whole numbers from 1 to 1000, pack_timeout whole seconds from "1s" to "3600s", and pack_cloud_sql_instances at most 10. New: pack_secret_readers, the Secret Manager secrets a pack's env names as cloud secrets, and orchestrator_key_version, which is null by default and leaves the pack orchestrator out until it's set, with the output orchestrator_key_steps. service_accounts names server, pack and orchestrator (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, use isDefault, GET /v1/projects/default or client.projects.getDefault(), never the name or the slug default.

  • A write whose database fails answers 500, not 404 or 409. 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 answered 404 when the database failed, as if what they named weren't there. Publishing a test set answered 409, as if it were already there. They now answer 500 and change nothing. A session whose activity can't be recorded is logged at WARN, 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/deployments says 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.
  • A release gate's cases.noNewFailures doesn't count a case whose answer couldn't be checked, even if its decisions failed. Its message says how many cases it checked.
  • 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's KINDGI_DATABASE_SERVER_CA as (known after apply): it's still the instance's CAs (Upgrade by hand).
  • Eighteen new migrations: four new tables (block_version_prs, env_cloud_secrets, run_files and tool_file_tokens), new columns that are empty or have a fixed default, with nothing rewritten, and the supervisor_fix_proposals table 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, orgs and projects. 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 keeps judgments locked 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 indexes eval_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 identity storage.buckets.get on it before you upgrade. The upgraded runtime reads the bucket's settings at start, and roles/storage.objectAdmin doesn't grant that permission, so without it the runtime refuses to start. Grant roles/storage.legacyBucketReader on the bucket, or add the permission to a custom role. A ledger or purge-record bucket needs only storage.objects.create.

  • With KINDGI_ARTIFACTS set, 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.yml sets ulimits: core: 0; elsewhere, use --ulimit core=0 with docker run, or LimitCORE=0 in 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 logs could not bring store <id> up to the current model (or could 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 new turn_invoker relation 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 a kindgi_remember in their Ask waits for a yes from then on. A sign-in whose store refuses the write logs a WARN, 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 two authz-decision events on the tool: the invoke deny, as before, then the allow, whose evidence names turn_invoker.

  • Upgrading drops the old supervisor_fix_proposals table; at 0.3.x no route or job wrote to it.

  • Projects gain a sort_end_user_corrections column, 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 with sortEndUserCorrections: true on PATCH /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.judgments is its corrections, and the threshold's runs and judges are dropped, so it fires on the count of corrections alone. budget.maxCostUsd is its runCapUsd, monthlyCapUsd its monthCapUsd, and classWeights its from (as-recorded reads as everyone, and restricted-only as experts). Its objective, candidates and the rest of its budget are dropped. One saved for a segment improves the segment's whole project. One saved with no classWeights reads as experts. 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 its input from kindgi schedules get <schedule-id>, set from to everyone in it, and send all of it back with kindgi 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 ends cancelled. 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-policies is /v1/release-gates, and kindgi gate-policies is kindgi 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, /cost and /corrections, or the same under flows/<flow>/runs/<run>. A link to runs/<run> still opens the run, but runs/<run>/journal, /provenance, /cost and /judgments don't.
    • Quality is now Corrections: corrections, and corrections on each agent and flow. A link to quality answers Page not found, whatever its tab.
    • Suggested changes are at agents/<agent>/suggested-changes, which was agents/<agent>/proposals, and an Improve run at agents/<agent>/improve-runs/<run>, which was agents/<agent>/proposals/passes/<pass>.
    • A test run is at test-runs/<run>, which was eval-runs/<run>. The project's Test sets pages are gone: each agent has its test set, at agents/<agent>/test-set.
    • A new release gate is made at agents/<agent>/release-gates/new, which was agents/<agent>/gate-policies/new.
  • A pack's copy of the kindgi-using skill gives 0.3.x console links until it's refreshed. A pack keeps the skill copies it was made with. Once its @kindgi/cli is upgraded, kindgi dev refreshes each copy you haven't edited as it starts, and kindgi skills sync refreshes them any time (./kindgiw dev and ./kindgiw skills sync in a Java or Scala pack). A copy you edited is kept, and kindgi skills sync --force replaces it. Until then, an older copy gives a run's tabs as runs/<run>/cost and 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 was improvement-pass.finished, and its data is in data.improveRun, which was data.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's subjectKind is agent-pin, fact or supervisor:suggested-change, which were agent-promotion, memory-fact and supervisor: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.env still works, and the runtime says so at each start: move it into secretEnv. For each stdio endpoint registered with a credential in plaintext config.env, or with a secretRef, which a stdio server is never sent, the boot logs a WARN under mcp.env that names the endpoint and the secretEnv that replaces it; kindgi-runtime check mcp-env-credentials, and kindgi doctor's mcp-env check, list the same. Its config.env values now read back as "[redacted]", and registering one again with a credential in config.env is refused. To move one, store each config.env value as a secret (a secretRef is stored already), then unregister the endpoint and register it again with secretEnv (MCP servers). An HTTP MCP endpoint with secretEnv in the config file stops the boot: only a stdio server is given one.

  • The expert queue's records are logged under expert-queue, which was judging. In KINDGI_LOG_LEVELS, change judging=<level> to expert-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. With tenancy = "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's upgrade.sh makes the switch in one apply, and then prints the steps that finish it: mint the orchestrator's key, apply again with pack_image, pack_min_instances, pack_env and pack_secret_env out 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_instances instances 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 takes pack_min_instances: upgrade.sh's steps take it out of the var files, and in a module block that calls the module it's an error now, as pack_image, pack_env and pack_secret_env are.