@kindgi/sdk 0.1.4-rc.5 → 0.1.5-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -28,6 +28,8 @@ export { KindgiApiError, fromWire, notImplementedInPreview, notYetWired } from '
28
28
  export type { AuthError, ConflictError, GuardrailViolation, GuardrailViolationError, InvalidRequestError, NetworkError, NotFoundError, NotImplementedInPreviewError, NotYetWiredError, RateLimitedError, ServerError, KindgiError, } from '@kindgi/client';
29
29
  export { readSse, unwrapSseData } from '@kindgi/client';
30
30
  export type { SseEvent, SseReadOptions } from '@kindgi/client';
31
+ export { verifySignedExport } from '@kindgi/client';
32
+ export type { ExportSigningKey, SignedExportEnvelope, SignedExportVerification, VerifySignedExportOptions, } from '@kindgi/client';
31
33
  export { followRun, subscribeToRun } from '@kindgi/client';
32
34
  export type { FollowRunOptions, RunProgress, RunProgressEvent, SubscribeToRunOptions, } from '@kindgi/client';
33
35
  export { comparisonOf } from '@kindgi/client';
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIlE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,YAAY,CAE/E;AAGD,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,GAAG,EACH,UAAU,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,0BAA0B,EAC1B,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,cAAc,EACd,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChG,YAAY,EACV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIlE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,YAAY,CAE/E;AAGD,YAAY,EACV,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,GAAG,EACH,UAAU,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,0BAA0B,EAC1B,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,cAAc,EACd,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChG,YAAY,EACV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC"}
package/dist/client.js CHANGED
@@ -50,6 +50,8 @@ export function createClient(options = {}) {
50
50
  export { KindgiApiError, fromWire, notImplementedInPreview, notYetWired } from '@kindgi/client';
51
51
  // ---- Streaming helpers (SSE parser + resume) ----
52
52
  export { readSse, unwrapSseData } from '@kindgi/client';
53
+ // ---- Signed exports: check one where it's read ----
54
+ export { verifySignedExport } from '@kindgi/client';
53
55
  // ---- Following a run (browser-safe: a page follows a run with a public token) ----
54
56
  export { followRun, subscribeToRun } from '@kindgi/client';
55
57
  // ---- Comparisons (a test set compared with a version): the typed result ----
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC;;;;;;;;;;;;;;;;;GAiBG;AAEH,6CAA6C;AAC7C,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkC,EAAE;IAC/D,OAAO,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,CAAC;AA8FD,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAgBhG,oDAAoD;AACpD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGxD,qFAAqF;AACrF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQ3D,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC;;;;;;;;;;;;;;;;;GAiBG;AAEH,6CAA6C;AAC7C,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkC,EAAE;IAC/D,OAAO,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3D,CAAC;AA8FD,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAgBhG,oDAAoD;AACpD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGxD,sDAAsD;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAQpD,qFAAqF;AACrF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQ3D,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kindgi/sdk",
3
- "version": "0.1.4-rc.5",
3
+ "version": "0.1.5-rc.0",
4
4
  "description": "@kindgi/sdk — the authoring SDK for Kindgi™. Facade over the individual @kindgi/* packages + @kindgi/client. Unifies pack authoring (defineTool / defineCheck / defineAgent / defineFlow) and client callsites (createClient) behind three sub-paths: /define, /client, /types. Re-export facade; zero behavior.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -55,15 +55,15 @@
55
55
  "README.md"
56
56
  ],
57
57
  "dependencies": {
58
- "@kindgi/agents": "0.1.4-rc.5",
59
- "@kindgi/client": "0.1.4-rc.5",
60
- "@kindgi/crypto": "0.1.4-rc.5",
61
- "@kindgi/flow": "0.1.4-rc.5",
62
- "@kindgi/guardrails": "0.1.4-rc.5",
63
- "@kindgi/handler-runtime": "0.1.4-rc.5",
64
- "@kindgi/schema": "0.1.4-rc.5",
65
- "@kindgi/tools": "0.1.4-rc.5",
66
- "@kindgi/types": "0.1.4-rc.5"
58
+ "@kindgi/agents": "0.1.5-rc.0",
59
+ "@kindgi/client": "0.1.5-rc.0",
60
+ "@kindgi/crypto": "0.1.5-rc.0",
61
+ "@kindgi/flow": "0.1.5-rc.0",
62
+ "@kindgi/guardrails": "0.1.5-rc.0",
63
+ "@kindgi/handler-runtime": "0.1.5-rc.0",
64
+ "@kindgi/schema": "0.1.5-rc.0",
65
+ "@kindgi/tools": "0.1.5-rc.0",
66
+ "@kindgi/types": "0.1.5-rc.0"
67
67
  },
68
68
  "peerDependencies": {
69
69
  "zod": "^4.0.0"
@@ -12,7 +12,7 @@ description: >
12
12
  kindgi-authoring-guardrails.
13
13
  type: core
14
14
  library: "@kindgi/sdk"
15
- version: "0.4.3"
15
+ version: "0.4.5"
16
16
  sdk_version: "0.0.0"
17
17
  pack_languages: [node]
18
18
  sources:
@@ -125,10 +125,10 @@ export default defined.value;
125
125
  capability-based selection when the preferred provider is
126
126
  unregistered or filtered out.
127
127
  - **`preferredModel`** — optional soft hint at the model level: set to
128
- a `ModelInfo.name` (e.g. `'gemini-2.5-pro'`), the router prefers
128
+ a `ModelInfo.name` (e.g. `'gemini-3.8-flash'`), the router prefers
129
129
  `(provider, model)` tuples whose model matches. To require a model
130
130
  rather than prefer it, add a hard requirement to the capability:
131
- `capabilities: [{ needs: [{ feature: 'tool-use' }, { models: { allow: ['gemini-2.5-pro'] } }] }]`.
131
+ `capabilities: [{ needs: [{ feature: 'tool-use' }, { models: { allow: ['gemini-3.8-flash'] } }] }]`.
132
132
  - **`conversationPolicy`** — optional. Absent = each turn loads the
133
133
  conversation's full history and no HITL gates apply. `historyLimit`
134
134
  caps how many prior messages are loaded; `hitl` configures approval
@@ -160,6 +160,30 @@ export default defined.value;
160
160
  retries the turn fails as before, with `toolRetries` on the error. A
161
161
  tenant's `tool-errors` policy can lower these (fewer retries, fewer
162
162
  kinds), never raise them.
163
+ - **`retrieval`** — what the agent reads from memory before each turn.
164
+ Empty = no memory. Each intent is
165
+ `{ types: ['acme.preference'], scope, mode?, limit? }`, with `scope`
166
+ one of `'same-user'`, `'same-conversation'`, `'same-project'`,
167
+ `'tenant'` (always within what the run may see), and `mode` absent
168
+ (newest first), `'keyword'`, `'semantic'` or `'both'`. Retrieved facts
169
+ reach the model as data in a `<memory>` block, never as instructions.
170
+ `semantic`/`both` need embeddings on the runtime
171
+ (`KINDGI_MEMORY_EMBEDDINGS`): without them a `semantic` intent fails
172
+ the turn (`semantic-unavailable`). `{ source: 'conversations', scope:
173
+ 'same-user' }` recalls this agent's earlier conversations: the people's
174
+ own words only, unless `roles: ['user', 'agent']` (its own earlier
175
+ answers come back marked unverified). `same-segment`/`same-project`
176
+ recall other people's conversations, and publishing warns.
177
+ - **`memory`** — `{ remember: { types, scope, keepDays? } }` gives the
178
+ turn the built-in tool `kindgi_remember` (name it exactly so in the
179
+ instructions; built-ins have no dots). The model picks the type, the
180
+ text, an optional `key` and an expiry; never the scope. A fact wider
181
+ than one person, or text that reads like an instruction, waits for a
182
+ person's approval. Remembering is a tool call, so use a model with
183
+ reliable tool calling. `{ instructionTypes: ['acme.policy'] }` turns a
184
+ retrieved, verified fact of those types into an instruction
185
+ ("Policies (verified)"). See
186
+ https://docs.kindgi.com/v0.1/guides/agents/give-an-agent-memory/.
163
187
 
164
188
  ## What a turn receives
165
189
 
@@ -15,7 +15,7 @@ description: >
15
15
  kindgi-authoring-agents.
16
16
  type: core
17
17
  library: "@kindgi/sdk"
18
- version: "0.3.6"
18
+ version: "0.3.8"
19
19
  sdk_version: "0.0.0"
20
20
  pack_languages: [node]
21
21
  sources:
@@ -55,7 +55,11 @@ before the response is stored.
55
55
  - **Built-in checks** (`BUILT_IN_CHECK_IDS` in `@kindgi/guardrails`):
56
56
  `must-cite`, `never-call-tool`, `max-tool-calls`, `output-matches`,
57
57
  `tool-order`, `required-substring`, `forbidden-substring`. A guardrail
58
- can name one of these instead of shipping its own check.
58
+ can name one of these (`check: 'forbidden-substring'`) instead of
59
+ shipping its own check, and the runtime runs the built-in. Their ids
60
+ are reserved: a pack that ships its own check under one is refused
61
+ (`reserved-check-id`), so name yours `<pack>.checks.<name>`. See
62
+ "Using a built-in check" below for each one's `config`.
59
63
 
60
64
  `@kindgi/sdk` exports `defineCheck` but no helper for the guardrail
61
65
  itself: a pack file default-exports the declaration as a plain object.
@@ -119,6 +123,46 @@ How the pack tooling reads this file:
119
123
  declares no config gets them all), and a config that doesn't fit
120
124
  refused, naming where.
121
125
 
126
+ ## Using a built-in check
127
+
128
+ Name the built-in as the guardrail's `check`, give its `config`, and ship
129
+ no check implementation:
130
+
131
+ ```ts
132
+ // guardrails/no-guarantees/index.ts
133
+ export default {
134
+ id: 'acme.no-guarantees',
135
+ name: 'Never promise a guarantee',
136
+ kind: 'zero-llm',
137
+ check: 'forbidden-substring',
138
+ config: { patterns: ['guaranteed', 'we promise'] },
139
+ action: { 'on-violation': 'halt' },
140
+ severity: 'error',
141
+ };
142
+ ```
143
+
144
+ Each built-in's `config` (tool lists hold tool ids, as in
145
+ `acme.fetch-precedent`; a setting without `?` is required):
146
+
147
+ | Check | Fails when | `config` |
148
+ | --- | --- | --- |
149
+ | `must-cite` | the answer is empty, or has fewer than `minCitations` matches of `sourcePattern` | `minCitations?: integer ≥ 1` (1), `sourcePattern?: string` (a regex; `[…]`-style citations by default) |
150
+ | `never-call-tool` | the turn called any tool in `tools` | `tools: (string \| { id, version? })[]`, one or more |
151
+ | `max-tool-calls` | the turn made more than `max` tool calls | `max?: integer ≥ 0` (10) |
152
+ | `output-matches` | the answer doesn't match `pattern` (with `negate: true`, it does) | `pattern: string` (a regex), `flags?: string` (letters `dgimsuyv`), `negate?: boolean` |
153
+ | `tool-order` | the tools in `sequence` weren't called in that order (others may come between) | `sequence: string[]`, one or more |
154
+ | `required-substring` | the answer is empty, or lacks any of `patterns` | `patterns: string[]`, one or more non-empty (plain text), `caseSensitive?: boolean` (false) |
155
+ | `forbidden-substring` | the answer contains any of `patterns` | `patterns: string[]`, one or more non-empty (plain text), `caseSensitive?: boolean` (false) |
156
+
157
+ A config the check doesn't take is refused: a required setting left out,
158
+ the wrong type, a setting the check doesn't know, or a regex that doesn't
159
+ compile. Registering it answers `422 guardrail-config-invalid` (each
160
+ problem in `details.issues`); deploying a pack with one fails with
161
+ `deployment-validation-failed`; one that still reaches a turn is a check
162
+ that can't run (`invalid-check-config`), so a `halt` guardrail stops the
163
+ turn. Each built-in's JSON Schema is its registered check's
164
+ `configSchema`.
165
+
122
166
  ## Validating a declaration in-process
123
167
 
124
168
  `defineGuardrail(spec, checks)` from `@kindgi/guardrails` validates a
@@ -17,9 +17,9 @@ description: >
17
17
  `kindgi secrets set` flow.
18
18
  type: core
19
19
  library: "@kindgi/sdk"
20
- version: "0.3.0"
20
+ version: "0.3.2"
21
21
  sdk_version: "0.0.0"
22
- pack_languages: [node, python]
22
+ pack_languages: [node, python, java, scala]
23
23
  ---
24
24
 
25
25
  # Wiring an MCP server for a Kindgi pack
@@ -28,7 +28,8 @@ pack_languages: [node, python]
28
28
  > (`@kindgi/cli`), not a global command. Run it through the project's
29
29
  > package manager — `pnpm exec kindgi …`, `npx --no kindgi …` (npm),
30
30
  > `yarn kindgi …` or `bun run kindgi …`. A Python pack (`[tool.kindgi]` in
31
- > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`.
31
+ > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`. A Java
32
+ > or Scala pack (`kindgi.config.json`) runs the CLI it pins: `./kindgiw …`.
32
33
  > Commands below are written `kindgi …` for brevity.
33
34
 
34
35
  If the user has an external resource (Postgres DB, GitHub org, Notion
@@ -89,7 +90,8 @@ Three moving parts:
89
90
  (`"command": "pnpm", "args": ["exec", "kindgi", "mcp-launch", …]`;
90
91
  npm: `npx --no kindgi …`) — never a global `kindgi`, never a
91
92
  download. A Python pack has no Node project, so its entries run the
92
- `kindgi` on `PATH` (`"command": "kindgi", "args": ["mcp-launch", …]`).
93
+ `kindgi` on `PATH` (`"command": "kindgi", "args": ["mcp-launch", …]`). A
94
+ Java or Scala pack's run the CLI it pins (`"command": "./kindgiw"`).
93
95
  The file is safe to commit — it references secrets by NAME, not
94
96
  value.
95
97
  3. **The launcher** — `kindgi mcp-launch` is what the coding agent
@@ -5,8 +5,9 @@ description: >
5
5
  can actually call a real model. Covers four paths — hosted via
6
6
  Anthropic native adapter, Gemini on Vertex AI (Google Application
7
7
  Default Credentials, no API key), hosted via the OpenAI-compat adapter
8
- (works with OpenAI + Groq + Together + Fireworks + OpenRouter +
9
- Ollama + vLLM + any other OpenAI-compatible endpoint), and local
8
+ (works with OpenAI, Groq, self-hosted vLLM and Ollama, and any other
9
+ OpenAI-compatible endpoint, a hosted gateway such as OpenRouter
10
+ included), and local
10
11
  via the in-process ONNX adapter — plus the credential flow (in
11
12
  `kindgi dev` the key lives in the project's env files — `.env`, then
12
13
  `.env.local` — added by hand or with `kindgi secrets set`'s no-echo
@@ -22,9 +23,9 @@ description: >
22
23
  kindgi-getting-started.
23
24
  type: core
24
25
  library: "@kindgi/sdk"
25
- version: "0.9.5"
26
+ version: "0.9.11"
26
27
  sdk_version: "0.0.0"
27
- pack_languages: [node, python]
28
+ pack_languages: [node, python, java, scala]
28
29
  sources:
29
30
  - packages/adapters/model-anthropic/src/provider.ts
30
31
  - packages/adapters/model-gemini/src/provider.ts
@@ -40,7 +41,8 @@ sources:
40
41
  > (`@kindgi/cli`), not a global command. Run it through the project's
41
42
  > package manager — `pnpm exec kindgi …`, `npx --no kindgi …` (npm),
42
43
  > `yarn kindgi …` or `bun run kindgi …`. A Python pack (`[tool.kindgi]` in
43
- > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`.
44
+ > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`. A Java
45
+ > or Scala pack (`kindgi.config.json`) runs the CLI it pins: `./kindgiw …`.
44
46
  > Commands below are written `kindgi …` for brevity.
45
47
 
46
48
  An **agent** is a versioned declaration; it needs a **provider** to run.
@@ -75,8 +77,9 @@ Three moving parts:
75
77
  1. **API key on disk** — in `kindgi dev` (environment `local`) the dotenv
76
78
  secret binding reads the project's own env files: `.env`, then
77
79
  `.env.local` on top (change the list with `dev.envFiles` in
78
- `kindgi.config.ts`, or `envFiles` under `[tool.kindgi.dev]` in a Python
79
- pack's `pyproject.toml`). A key already in the app's `.env` just works.
80
+ `kindgi.config.ts`, `envFiles` under `[tool.kindgi.dev]` in a Python
81
+ pack's `pyproject.toml`, or `dev.envFiles` in a Java or Scala pack's
82
+ `kindgi.config.json`). A key already in the app's `.env` just works.
80
83
  `kindgi secrets set` (interactive, no-echo) writes `.env.local`. For
81
84
  non-sensitive values (log levels, region names, feature flags),
82
85
  `kindgi env set NAME VALUE --env=local` writes the same file with a
@@ -106,7 +109,11 @@ yours.
106
109
  ## Path A — Hosted, native Anthropic
107
110
 
108
111
  Best fidelity to Anthropic's API (prompt caching, latest models, tool
109
- use, structured output). Requires an `ANTHROPIC_API_KEY`.
112
+ use). Requires an `ANTHROPIC_API_KEY`.
113
+
114
+ A model's `structured-output` feature is a routing label: the model can
115
+ follow a JSON schema natively, but Kindgi's typed outputs use instructions,
116
+ then parse, check against the schema and repair, on every provider.
110
117
 
111
118
  **Step 1 — set the key:**
112
119
  ```sh
@@ -123,9 +130,19 @@ credential on argv.
123
130
 
124
131
  **Step 2 — register it, from the preset:**
125
132
  ```sh
126
- kindgi providers register --preset=anthropic # Opus 5.5, Sonnet 5.5, Haiku 4.5
127
- kindgi providers register --preset=anthropic --models=claude-haiku-4-5 # just one
133
+ kindgi providers register --preset=anthropic # Opus 5.5, Sonnet 5.5 (default), Haiku 5.5, Haiku 4.5
134
+ kindgi providers register --preset=anthropic --models=claude-sonnet-5-5 # just one
128
135
  ```
136
+ Before pinning a Claude model, check its status on Anthropic's model
137
+ deprecations page (https://platform.claude.com/docs/en/about-claude/model-deprecations): a turn routed to a retired model fails. Prefer the
138
+ preset's default. Each
139
+ preset names a default model (`metadata.defaultModel`, marked `(default)`
140
+ when it registers), which an agent with no preference gets. A preset
141
+ registered before 0.1.4 has none: unregister it and register it again.
142
+ The Claude 5.5 and GPT-6 models take no `temperature` (`"sampling": false`:
143
+ the call goes without it, with a `sampling-unsupported` warning), and a
144
+ model's `thinking` says how it thinks; thinking counts against
145
+ `maxOutputTokens` and bills as output.
129
146
  The preset carries the models, context windows, output limits and current
130
147
  prices (`kindgi providers presets` lists the presets and when their prices
131
148
  were checked); `--max-output-tokens=<n>` sets another output limit. In a pack it refuses until the key is in the pack's env files —
@@ -139,8 +156,8 @@ needs under `kindgi dev`:
139
156
  ```ts
140
157
  // in kindgi.config.ts
141
158
  providers: [
142
- { preset: 'anthropic', models: ['claude-haiku-4-5'] }, // key ANTHROPIC_API_KEY, from the env files
143
- { preset: 'gemini', project: 'acme-gcp', models: ['gemini-2.5-flash'] },
159
+ { preset: 'anthropic', models: ['claude-sonnet-5-5'] }, // key ANTHROPIC_API_KEY, from the env files
160
+ { preset: 'gemini', project: 'acme-gcp', models: ['gemini-3.8-flash'] },
144
161
  { spec: { /* the provider.json body below */ } },
145
162
  ],
146
163
  ```
@@ -148,14 +165,17 @@ providers: [
148
165
  # in pyproject.toml: one table per provider, same keys
149
166
  [[tool.kindgi.providers]]
150
167
  preset = "anthropic"
151
- models = ["claude-haiku-4-5"]
168
+ models = ["claude-sonnet-5-5"]
152
169
  ```
170
+ In a Java or Scala pack's `kindgi.config.json`, the same keys:
171
+ `"providers": [{"preset": "anthropic", "models": ["claude-sonnet-5-5"]}]`.
153
172
  - A preset entry takes `models`, `project`, `secret` (the key's name, in place
154
- of the preset's) and `maxOutputTokens`, spelled the same in `pyproject.toml`;
173
+ of the preset's) and `maxOutputTokens`, spelled the same in `pyproject.toml`
174
+ and `kindgi.config.json`;
155
175
  a `spec` entry is a `--spec` body. A
156
176
  key is always a secret's name (`secret_ref`); a credential in
157
177
  `adapter_config` is refused.
158
- - Each boot prints `Providers from kindgi.config.ts:` with one line each:
178
+ - Each boot prints `Providers from kindgi.config.ts:` (the pack's config file) with one line each:
159
179
  `registered`, `unchanged`, `registered again (changed in kindgi.config.ts)`,
160
180
  `unregistered (no longer in kindgi.config.ts)`, or ⚠ `not registered: <KEY>
161
181
  is not in .env, .env.local` (set the key, then restart: the config isn't
@@ -167,7 +187,7 @@ models = ["claude-haiku-4-5"]
167
187
  providers with `kindgi providers register`.
168
188
 
169
189
  **Step 2 (by hand) — write `provider.json`** at the pack root. One connection,
170
- three models — matches how the Anthropic SDK actually works (the API
190
+ two models — matches how the Anthropic SDK actually works (the API
171
191
  key is per-vendor; the model is per-call):
172
192
  ```json
173
193
  {
@@ -194,16 +214,6 @@ key is per-vendor; the model is per-call):
194
214
  "completionUsdPer1kTokens": 0.01
195
215
  },
196
216
  "description": "Balanced performance/cost."
197
- },
198
- {
199
- "name": "claude-haiku-4-5",
200
- "contextWindow": 200000,
201
- "features": ["tool-use"],
202
- "cost": {
203
- "promptUsdPer1kTokens": 0.001,
204
- "completionUsdPer1kTokens": 0.005
205
- },
206
- "description": "Fastest and cheapest — routing, classification, simple calls."
207
217
  }
208
218
  ],
209
219
  "description": "Anthropic Claude via native adapter."
@@ -261,9 +271,9 @@ Works with **any** OpenAI-compatible endpoint. Same adapter, different
261
271
  | Groq | `https://api.groq.com/openai/v1` |
262
272
  | Together | `https://api.together.xyz/v1` |
263
273
  | Fireworks | `https://api.fireworks.ai/inference/v1` |
264
- | OpenRouter | `https://openrouter.ai/api/v1` |
265
274
  | DeepSeek | `https://api.deepseek.com/v1` |
266
275
  | LiteLLM proxy | `http://localhost:4000/v1` |
276
+ | OpenRouter (a hosted gateway) | `https://openrouter.ai/api/v1` |
267
277
 
268
278
  The connection carries the `baseURL` (in `adapter_config`);
269
279
  each endpoint is a separate provider row because each has its own API
@@ -485,24 +495,16 @@ outside Google Cloud: put a service-account key (its JSON) in a secret
485
495
  "region": "global",
486
496
  "models": [
487
497
  {
488
- "name": "gemini-2.5-pro",
498
+ "name": "gemini-3.8-flash",
489
499
  "contextWindow": 1048576,
490
- "features": ["tool-use"],
500
+ "features": ["tool-use", "structured-output", "long-context"],
491
501
  "maxOutputTokens": 65536,
492
- "cost": {
493
- "promptUsdPer1kTokens": 0.00125,
494
- "completionUsdPer1kTokens": 0.01,
495
- "longContext": {
496
- "thresholdTokens": 200000,
497
- "promptUsdPer1kTokens": 0.0025,
498
- "completionUsdPer1kTokens": 0.015
499
- }
500
- }
502
+ "cost": { "promptUsdPer1kTokens": 0.00075, "completionUsdPer1kTokens": 0.00375 }
501
503
  },
502
504
  {
503
- "name": "gemini-2.5-flash",
505
+ "name": "gemini-3.5-flash-lite",
504
506
  "contextWindow": 1048576,
505
- "features": ["tool-use"],
507
+ "features": ["tool-use", "structured-output", "long-context"],
506
508
  "maxOutputTokens": 65536,
507
509
  "cost": { "promptUsdPer1kTokens": 0.0003, "completionUsdPer1kTokens": 0.0025 }
508
510
  }
@@ -517,11 +519,17 @@ outside Google Cloud: put a service-account key (its JSON) in a secret
517
519
  - `metadata.region` is the Vertex location: `global`, or a region such as
518
520
  `us-central1` or `northamerica-northeast1` when data must stay in one
519
521
  place. `unspecified` means `global`. Different locations are different
520
- provider rows.
522
+ provider rows. Check that the location serves the model: Gemini 3.8 Flash
523
+ isn't served from `us-central1`.
524
+ - Don't register `gemini-2.5-pro` or `gemini-2.5-flash`: Vertex AI retires
525
+ both on 2026-10-20.
521
526
  - Rates are per 1K tokens, from Google's published pricing; check them
522
- before relying on budgets. Thinking tokens bill as output.
523
- `longContext` switches the whole call to the higher rates past the
524
- threshold; `cachedPromptMultiplier` (default 0.25) prices cached
527
+ before relying on budgets. Thinking tokens bill as output, and Gemini 3.8
528
+ Flash thinks by default. `gemini-3.8-flash`'s rates above are Google's
529
+ launch price, through 2026-12-31 ($0.0015 / $0.0075 from 2027-01-01).
530
+ `longContext` (`{ thresholdTokens, promptUsdPer1kTokens,
531
+ completionUsdPer1kTokens }` in a model's `cost`) switches the whole call
532
+ to the higher rates past the threshold; `cachedPromptMultiplier` (default 0.25) prices cached
525
533
  prompt tokens.
526
534
 
527
535
  **Step 3 — register and check:**
@@ -533,7 +541,8 @@ Or skip step 2: `kindgi providers register --preset=gemini --project=<your-gcp-p
533
541
  registers both models above.
534
542
  Then pin it from an agent with `preferredProvider: 'gemini'` (and a model
535
543
  with `preferredModel`; in Python, `preferred_provider="gemini"` and
536
- `preferred_model=…`), or let the router pick by capability.
544
+ `preferred_model=…`; in Java, `.set("preferredProvider", "gemini")`), or let
545
+ the router pick by capability.
537
546
 
538
547
  ## How the router picks between multiple providers + models
539
548
 
@@ -548,13 +557,16 @@ tenant policy), then sorts survivors in this order:
548
557
  - Only `preferredModel` set → promote any provider exposing that model.
549
558
  - Only `preferredProvider` set → promote every model of that provider.
550
559
  `defineAgent` takes both (`preferredProvider`, `preferredModel`), and
551
- so does a Python `Agent` (`preferred_provider=`, `preferred_model=`).
560
+ so does a Python `Agent` (`preferred_provider=`, `preferred_model=`) and
561
+ a Java `Agent.define(…)` (`set("preferredProvider", …)`).
552
562
  2. **`capability.prefer[]` weights.** If the agent's capability
553
563
  declares `prefer: [{feature: 'thinking', weight: 3}, ...]`, tuples
554
564
  with matching model features (or provider attributes) get higher
555
565
  scores. Sorted by summed score, descending.
556
- 3. **Deterministic lexical tiebreak.** When scores tie, tuples sort by
557
- `(providerId, modelName)` alphabetically — replay-safe and stable.
566
+ 3. **Deterministic tiebreak.** When scores tie, tuples sort by provider
567
+ id, then the provider's `defaultModel` before its other models, then
568
+ model name — replay-safe and stable. A provider without a
569
+ `defaultModel` falls back to its first model by name.
558
570
 
559
571
  **Practical rule:** preferences are soft — they rank, they don't
560
572
  exclude. To guarantee which model runs, make it a hard requirement in
@@ -645,7 +657,8 @@ defineAgent({
645
657
  be the FULL npm package name of the adapter — `"@kindgi/adapter-model-anthropic"`,
646
658
  NOT `"anthropic"`. Adapters are registered with the runtime under
647
659
  their full package names, and a short name matches none of them, so
648
- the registration fails. The model adapters are
660
+ registering is refused: the runtime has no adapter by that name
661
+ (`✗ /adapter_id: …`). The model adapters are
649
662
  `@kindgi/adapter-model-anthropic`, `@kindgi/adapter-model-gemini`,
650
663
  `@kindgi/adapter-model-openai-compat` and
651
664
  `@kindgi/adapter-model-in-process`; `kindgi providers presets` shows
@@ -682,8 +695,9 @@ defineAgent({
682
695
  Then re-register.
683
696
 
684
697
  6. **Key not found by the runtime.** `kindgi dev` reads the env files
685
- at the PACK ROOT (the directory with `kindgi.config.ts`, or a Python
686
- pack's `pyproject.toml` with `[tool.kindgi]`) — `.env` and
698
+ at the PACK ROOT (the directory with `kindgi.config.ts`, a Python
699
+ pack's `pyproject.toml` with `[tool.kindgi]`, or a Java or Scala pack's
700
+ `kindgi.config.json`) — `.env` and
687
701
  `.env.local`, or whatever `dev.envFiles` lists; the boot log prints
688
702
  which files it found. A `KINDGI_`-prefixed name is Kindgi runtime
689
703
  config and never resolves as a secret. Outside `kindgi dev`, the
@@ -712,6 +726,21 @@ defineAgent({
712
726
  that names nothing registered, and the tenant's policy. `kindgi
713
727
  providers list` shows what is registered.
714
728
 
729
+ 10. **A setting the adapter can't use.** Registering checks the spec
730
+ against its adapter (no network call, no key read) and refuses what
731
+ it can't use: `422 provider-config-invalid`, nothing stored, one line
732
+ per problem with its JSON-pointer path:
733
+ ```text
734
+ Error [invalid-request]: Provider "ollama" doesn't fit adapter @kindgi/adapter-model-openai-compat: adapter_config.api must be one of responses, chat-completions.
735
+ ✗ /adapter_config/api: adapter_config.api must be one of responses, chat-completions.
736
+ ```
737
+ Fix each `✗` line's setting and register again. A key the adapter
738
+ needs is checked too (`✗ /secret_ref: …`); whether the key works, or
739
+ the endpoint answers, isn't (the first turn finds out). A
740
+ registration stored before 0.1.5 wasn't checked: `kindgi doctor`
741
+ names its problems (`GET /v1/providers/<id>/check`); unregister it
742
+ and register it again.
743
+
715
744
  ## Verifying end-to-end
716
745
 
717
746
  ```sh
@@ -132,6 +132,32 @@ const defined = defineTool({
132
132
 
133
133
  The runtime resolves every declared secret on every call, for the call's tenant, in its env (`KINDGI_ENV`; in `kindgi dev`, `local`: the pack's `.env` and `.env.local`). It checks each value against its schema, and fails the call, naming the secret, when one is missing or doesn't match. Every declared secret is required, so in a runtime call `ctx.secrets` holds them all; it's optional in the type because a unit test builds its own context and passes `secrets: { CITATOR_KEY: '…' }`.
134
134
 
135
+ A value that differs per tenant, org or project but isn't secret (a base URL, a region, an account id) is an **env value**: declared in `needsSpec.env`, read from `ctx.env`:
136
+
137
+ ```ts
138
+ const defined = defineTool({
139
+ // …id, description, version, input, output, effects…
140
+ needsSpec: {
141
+ env: {
142
+ ORDERS_BASE_URL: { type: 'string', pattern: '^https://' },
143
+ ORDERS_REGION: { type: 'string', enum: ['eu', 'us'], default: 'eu' },
144
+ },
145
+ },
146
+ handler: async ({ orderId }, ctx) => ({
147
+ url: `${ctx.env?.ORDERS_BASE_URL}/${ctx.env?.ORDERS_REGION}/orders/${orderId}`,
148
+ }),
149
+ });
150
+ ```
151
+
152
+ - **Which value a call gets:** its project's, else its org's, else the tenant's, in the runtime's env; a schema `default` makes a name optional. The values a call used are recorded with it, so a retry or a resume sees the same ones.
153
+ - **Setting them:** `kindgi env set ORDERS_REGION us --scope=project:<project-id> --env=local` (or `--scope=tenant`, for every project). Changing a value that's already set takes `--force`.
154
+ - **A declared value nobody set** stops the call before the tool runs. For a tool `acme-orders.needs-account` that declares `ACME_ACCOUNT_ID`, the message reads:
155
+ ```text
156
+ precondition-failed: Tool "acme-orders.needs-account" was not run: env-value-missing: tool "acme-orders.needs-account" needs env value "ACME_ACCOUNT_ID" in env "local", and none is set for project e889c1f5-eae7-45dc-8669-5bd029a5d85c, its org, or the tenant. Set it: kindgi env set ACME_ACCOUNT_ID <value> --scope=project:e889c1f5-eae7-45dc-8669-5bd029a5d85c --env=local (or --scope=tenant, for every project)
157
+ ```
158
+ - **Not secret:** env values are recorded with each run that uses them and shown in its journal. A credential is a secret (`needsSpec.secrets`), never an env value.
159
+ - **In a unit test:** pass `env: { … }` in the context `invokeTool` gets.
160
+
135
161
  Everything else comes from the process environment: `process.env.CITATOR_URL`. The pack service runs with the pack's env files in `kindgi dev`, and with the container's environment in an image. Declare the names your code reads in `kindgi.config.ts`, `env: { required: ['CITATOR_URL'], optional: [...] }`: a deployment injects exactly those, a pack service missing a required one isn't ready and says which, and `kindgi dev` warns about it. Values per environment go in `environments.<name>.env`, secrets only as references.
136
162
 
137
163
  ## Declarative HTTP spec
@@ -14,9 +14,9 @@ description: >
14
14
  diagnostic output into durable input for framework improvement.
15
15
  type: core
16
16
  library: "@kindgi/sdk"
17
- version: "0.4.0"
17
+ version: "0.4.2"
18
18
  sdk_version: "0.0.0"
19
- pack_languages: [node, python]
19
+ pack_languages: [node, python, java, scala]
20
20
  ---
21
21
 
22
22
  # Capturing framework feedback
@@ -25,7 +25,8 @@ pack_languages: [node, python]
25
25
  > (`@kindgi/cli`), not a global command. Run it through the project's
26
26
  > package manager — `pnpm exec kindgi …`, `npx --no kindgi …` (npm),
27
27
  > `yarn kindgi …` or `bun run kindgi …`. A Python pack (`[tool.kindgi]` in
28
- > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`.
28
+ > `pyproject.toml`) has no Node project: run the `kindgi` on `PATH`. A Java
29
+ > or Scala pack (`kindgi.config.json`) runs the CLI it pins: `./kindgiw …`.
29
30
  > Commands below are written `kindgi …` for brevity.
30
31
 
31
32
  You just spent time diagnosing a Kindgi-framework issue. That diagnostic