Pack index
@kindgi/specs/pack-index.schema.json, schema version 1.7.0.
The index.json a pack build emits: the pack's tools, guardrails, agents, flows and data blocks as data, plus where each tool handler and guardrail check lives. A runtime registers the pack's primitives from it, and a pack service loads the modules it names and resolves every call by id. Any indexer (the TypeScript kindgi-index, the Python python -m kindgi.pack index) emits this shape. Determinism: every list is sorted by id (code-unit order), keys are sorted at every level, the file is UTF-8 JSON indented by two spaces with a trailing newline, and integral numbers carry no fraction, so the same source indexes to the same bytes. Consumers refuse an envelope v they don't recognize.
v(1, required): Envelope version. Additive fields on an existing entry shape don't bump it.packId(string, required): The pack's id (pack.idin the pack config).packVersion(string, required): The pack's version (pack.versionin the pack config).artifactVersion(string, required): This build of the pack. A pack build pins it; a local indexer defaults toYYYYMMDD.N(UTC date, N counting up from the previous index of the same day).publishedAt(string (date-time), required): When the index was built — ISO 8601 UTC with milliseconds (2026-09-20T14:32:07.104Z). A pack build pins it for reproducible output.tools(array of tool, required): Tools with handler code, sorted byid.guardrails(array of guardrail, required): Guardrails whose check is pack code, sorted byid.agents(array of agent, required): Agents, sorted byid.flows(array of flow, required): Flows, sorted byid.blocks(array of block): The pack's data blocks (schema-version 1.5.0+), sorted byid: each JSON file the blocks discovery pattern matches (blocks/**/*.jsonby default), one version per block. Absent when the pack has none. A deploy publishes them with the pack's agents.env(object): The process environment the pack's code reads (envinkindgi.config;[tool.kindgi.env]inpyproject.toml). Absent when the pack declares none. A deployment injects exactly these names. With arequiredname unset or empty, the pack service isn't ready (unless its env check iswarn);/readyzand/v1/infoname it. NotneedsSpec.env: that is per-call context.
Definitions
Section titled “Definitions”envName
Section titled “envName”A process environment variable name. KINDGI_* names configure Kindgi and are never a pack's.
Type: string
modulePath
Section titled “modulePath”The source file the primitive was declared in, relative to the pack root: forward slashes, no leading ./ (tools/echo/index.ts, tools/ledger.py). A pack service resolves it against its module root; a build may point it at a bundle instead. Several entries may share one module (a Python module can declare several tools).
Type: string
jsonSchema
Section titled “jsonSchema”A JSON Schema (Draft 2020-12) in wire form. Open: any JSON Schema keyword is allowed, so this node carries no additionalProperties restriction.
Type: object
openObject
Section titled “openObject”An object whose shape is defined by the primitive's own schema (tool.schema.json, guardrail.schema.json, agent.schema.json, flow.schema.json); the index carries it as declared.
Type: object
id(string, required): Tool id — what a pack service resolves aninvokeby.description(string): What the tool does — the model reads it.version(string): The tool's version. A caller that names a version getstool-version-mismatchwhen it differs.input(jsonSchema, required): JSON Schema the input must satisfy; the pack service validates before running the handler.output(jsonSchema, required): JSON Schema the handler's return value must satisfy; the pack service validates it.effects(array of openObject): Declared side effects (tool.schema.jsoneffects).needs(array of openObject): Declared needs (tool.schema.jsonneeds).needsSpec(openObject): Typed needs (tool.schema.jsonneedsSpec).sandbox(string): Isolation posture (tool.schema.jsonsandbox).limits(openObject): Resource limits (tool.schema.jsonlimits).network(openObject): Network policy (tool.schema.jsonnetwork).mutating(boolean): Whether the tool may change something (tool.schema.jsonmutating).falsemakes it read-only: it runs in a dry run, and per-tool approval gates don't ask before it by default. Absent means it may.needsApprovalWhenUnattended(boolean): Whether a person must say yes to every call of the tool in a run no person started, unless that run's trigger lists the tool in itstoolsAllowedUnattended(tool.schema.jsonneedsApprovalWhenUnattended). Absent meansfalse.pauses(boolean): Whether the tool may answerpause(tool.schema.jsonpauses, schema-version 1.6.0+): the runtime then sends each call awaitToken, and the run waits for another system's answer. Absent meansfalse.resultIsOutsideData(boolean): Whether the tool's results are outside data an agent reads as data, not instructions (tool.schema.jsonresultIsOutsideData). Absent meansfalse.spec(openObject): A declarative tool's spec (tool.schema.jsonspec, e.g.kind: 'http'). A runtime runs a tool that has one itself, resolving itssecretRefs, rather than calling the pack service.modulePath(modulePath, required)
guardrail
Section titled “guardrail”id(string, required): Guardrail id.name(string): Human-readable name.kind(string, required): How the guardrail is checked (guardrail.schema.jsonkind).action(openObject, required): What a violation does (guardrail.schema.jsonaction, withon-violation).severity(string): Severity (guardrail.schema.jsonseverity).scope(openObject): When the guardrail applies (guardrail.schema.jsonscope).at("before-tool"|"after-tool"|"model-step"|"final-answer"): Where in the agent's turn the guardrail runs (guardrail.schema.jsonat). Absent: the final answer.sees("turn"|"conversation"): What the check sees of the conversation (guardrail.schema.jsonsees). Absent: the turn.checkPoints(array of"before-tool"|"after-tool"|"model-step"|"final-answer"): The points the pack's check runs at (itsdefineCheckpoints, or the final answer when it names none), whichatis one of. Absent for a built-in check, whose points the runtime knows; for a pack check, absent means the final answer only.checkModulePath(modulePath, required)checkId(string): The check's id — what a pack service resolves acheck-invokeby. Absent: the guardrail'sid.checkBuiltIn(true): The guardrail names a built-in check (checkId) without shipping a check of its own:checkModulePathis only the file it's declared in. The CLI sets it; a runtime warns about a guardrail naming a built-in without it.configSchema(jsonSchema): JSON Schema of the check's config.config(openObject): What the check is configured with (guardrail.schema.jsonconfig).budget(openObject): What one check may spend (guardrail.schema.jsonbudget): the agent loop stops a check past itsmaxLatencyMs.judgeCapabilities(openObject): For anllm-judgeguardrail: what its judge model is routed by (guardrail.schema.jsonjudgeCapabilities). An indexer refuses anllm-judgeguardrail without it.sandbox(string): Isolation posture.limits(openObject): Resource limits.network(openObject): Network policy.
An agent as declared (agent.schema.json). A TypeScript pack's defineAgent checks it in full at build; a deploy checks only its shape, its instructions' template and its output schema.
id(string, required)version(string, required)name(string, required)instructions(one of the objects below, required)- string
- an object
prompt(string, required)version(string, required)
settings(array of any)modelSettings(object)capabilities(array of any, required)tools(array of object, required)id(string, required)version(string, required): Semver range.
retrieval(array of any)memory(openObject)guardrails(array of string)budget(openObject)parameters(array of any)preferredProvider(string)preferredModel(string)description(string)tags(array of string)conversationPolicy(object): As declared (agent.schema.jsonConversationPolicy), exceptautoCloseAfterInactiveSeconds, which is refused: a conversation never closes by itself, only when someone closes it.autoCloseAfterInactiveSeconds(object)
output(openObject): Typed output ({ schema, name?, maxRepairs? }), its schema already JSON Schema.toolErrors(openObject): How the agent's turns retry failed tool calls ({ maxRetries?, retryOn? },agent.schema.jsontoolErrors).parallelToolCalls(boolean): Whether read-only tool calls that a step asks for one after another run at the same time, up to 8 at once (agent.schema.jsonparallelToolCalls). A call to a read-only tool that pauses or declares connections runs on its own, since it may wait. Default true.modulePath(modulePath, required)
A data block as POST /v1/blocks publishes it: a prompt or settings, at one version. A prompt's templateFile is read into template when the pack is indexed, so the index holds the whole block. The runtime validates it in full (the template parses, the values satisfy their schema) when a deploy publishes it.
id(string, required): Dotted lowercase id, like an agent's (acme.reply-prompt).version(string, required): Plainmajor.minor.patch: the version a deploy publishes.kind("prompt"|"settings", required)description(string)content(object, required): A prompt's{ template, parameters? }, or settings'{ values, schema? }.modulePath(modulePath, required): The block's file, relative to the pack root (blocks/reply-prompt.json).
A flow as declared (flow.schema.json), plus the kernel payload version.
id(string, required)version(string, required)name(string)description(string)nodes(array of any, required)edges(array of any, required)maxParallelism(integer)metadata(openObject)output(openObject)kernelPayloadVersion(1, required): Version of the flow payload inside the index, independent of the envelopev.modulePath(modulePath, required)