@instruktlabs/kiln 0.0.0-stage → 1.0.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/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +19 -0
- package/.claude-plugin/plugin.json +30 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.mcp.json +10 -0
- package/CHANGELOG.md +2579 -0
- package/CONTRIBUTING.md +130 -0
- package/LICENSE +21 -0
- package/README.md +443 -2
- package/THIRD_PARTY_NOTICES.md +62 -0
- package/dist/agent-providers.mjs +310 -0
- package/dist/agent-run.mjs +40433 -0
- package/dist/build.json +215 -0
- package/dist/cli.mjs +48027 -0
- package/dist/evaluator-worker.mjs +27572 -0
- package/dist/mcp-engine.mjs +43537 -0
- package/dist/mcp-server.mjs +2388 -0
- package/dist/viewer/app.js +4281 -0
- package/dist/viewer/chat.html +4409 -0
- package/dist/viewer/index.html +51 -0
- package/dist/viewer/style.css +51 -0
- package/docs/architecture.md +77 -0
- package/docs/cameras.md +181 -0
- package/docs/chatgpt.md +48 -0
- package/docs/collections.md +195 -0
- package/docs/community-exporter.md +95 -0
- package/docs/engine-handoff.md +221 -0
- package/docs/examples.md +171 -0
- package/docs/export-profiles.md +223 -0
- package/docs/extending.md +43 -0
- package/docs/geometry.md +505 -0
- package/docs/google.md +121 -0
- package/docs/harnesses.md +372 -0
- package/docs/install.md +542 -0
- package/docs/material-library.md +133 -0
- package/docs/migration.md +809 -0
- package/docs/programs.md +123 -0
- package/docs/projects-and-live-review.md +94 -0
- package/docs/rendering.md +250 -0
- package/docs/runtime.md +223 -0
- package/docs/sdk.md +137 -0
- package/docs/tools.md +1874 -0
- package/lib/_types/render-service/src/build-identity.d.mts +24 -0
- package/lib/_types/render-service/src/instance.d.mts +47 -0
- package/lib/agent/call-budget.d.ts +55 -0
- package/lib/agent/call-budget.js +52 -0
- package/lib/agent/compaction.d.ts +83 -0
- package/lib/agent/compaction.js +124 -0
- package/lib/agent/concurrency.d.ts +8 -0
- package/lib/agent/concurrency.js +24 -0
- package/lib/agent/diff.d.ts +23 -0
- package/lib/agent/diff.js +124 -0
- package/lib/agent/generate.d.ts +192 -0
- package/lib/agent/generate.js +240 -0
- package/lib/agent/hooks.d.ts +91 -0
- package/lib/agent/hooks.js +158 -0
- package/lib/agent/index.d.ts +42 -0
- package/lib/agent/index.js +30 -0
- package/lib/agent/native-prompt.d.ts +15 -0
- package/lib/agent/native-prompt.js +29 -0
- package/lib/agent/native-workflow.d.ts +4 -0
- package/lib/agent/native-workflow.js +30 -0
- package/lib/agent/providers.d.ts +188 -0
- package/lib/agent/providers.js +392 -0
- package/lib/agent/run.d.ts +72 -0
- package/lib/agent/run.js +245 -0
- package/lib/agent/skill-resources.d.ts +9 -0
- package/lib/agent/skill-resources.js +178 -0
- package/lib/agent/split-tool-result-images.d.ts +33 -0
- package/lib/agent/split-tool-result-images.js +47 -0
- package/lib/agent/stream-start.d.ts +30 -0
- package/lib/agent/stream-start.js +32 -0
- package/lib/agent/tools.d.ts +12 -0
- package/lib/agent/tools.js +77 -0
- package/lib/agent/view-render-timeout.d.ts +40 -0
- package/lib/agent/view-render-timeout.js +71 -0
- package/lib/animation-cubic.d.ts +12 -0
- package/lib/animation-cubic.js +44 -0
- package/lib/animation-spline.d.ts +50 -0
- package/lib/animation-spline.js +168 -0
- package/lib/architecture.d.ts +146 -0
- package/lib/architecture.js +498 -0
- package/lib/arena/adaptive.d.ts +38 -0
- package/lib/arena/adaptive.js +87 -0
- package/lib/arena/bradley-terry.d.ts +63 -0
- package/lib/arena/bradley-terry.js +165 -0
- package/lib/arena/index.d.ts +15 -0
- package/lib/arena/index.js +13 -0
- package/lib/assembly-transform.d.ts +7 -0
- package/lib/assembly-transform.js +21 -0
- package/lib/assembly.d.ts +105 -0
- package/lib/assembly.js +587 -0
- package/lib/asset-catalog.d.ts +13 -0
- package/lib/asset-catalog.js +21 -0
- package/lib/asset-export.d.ts +41 -0
- package/lib/asset-export.js +106 -0
- package/lib/asset-materials-node.d.ts +5 -0
- package/lib/asset-materials-node.js +56 -0
- package/lib/asset-widget.d.ts +10 -0
- package/lib/asset-widget.js +23 -0
- package/lib/assets-node.d.ts +33 -0
- package/lib/assets-node.js +348 -0
- package/lib/assets-resources.d.ts +33 -0
- package/lib/assets-resources.js +109 -0
- package/lib/assets.d.ts +91 -0
- package/lib/assets.js +205 -0
- package/lib/atomic-directory.d.ts +9 -0
- package/lib/atomic-directory.js +31 -0
- package/lib/authoring-style.d.ts +3 -0
- package/lib/authoring-style.js +42 -0
- package/lib/build-cache-node.d.ts +12 -0
- package/lib/build-cache-node.js +87 -0
- package/lib/build-cache.d.ts +24 -0
- package/lib/build-cache.js +229 -0
- package/lib/character.d.ts +132 -0
- package/lib/character.js +612 -0
- package/lib/cli-render-mode.d.ts +31 -0
- package/lib/cli-render-mode.js +204 -0
- package/lib/community-exporter.d.ts +13 -0
- package/lib/community-exporter.js +237 -0
- package/lib/composer/agent/compaction.d.ts +72 -0
- package/lib/composer/agent/compaction.js +103 -0
- package/lib/composer/agent/index.d.ts +25 -0
- package/lib/composer/agent/index.js +19 -0
- package/lib/composer/agent/prompt.d.ts +25 -0
- package/lib/composer/agent/prompt.js +100 -0
- package/lib/composer/agent/run.d.ts +91 -0
- package/lib/composer/agent/run.js +212 -0
- package/lib/composer/agent/tools.d.ts +75 -0
- package/lib/composer/agent/tools.js +643 -0
- package/lib/composer/agent/world-run.d.ts +50 -0
- package/lib/composer/agent/world-run.js +295 -0
- package/lib/composer/agent/world-tools.d.ts +20 -0
- package/lib/composer/agent/world-tools.js +311 -0
- package/lib/composer/collision.d.ts +109 -0
- package/lib/composer/collision.js +339 -0
- package/lib/composer/contract-utils.d.ts +6 -0
- package/lib/composer/contract-utils.js +48 -0
- package/lib/composer/dsl.d.ts +52 -0
- package/lib/composer/dsl.js +147 -0
- package/lib/composer/ground.d.ts +22 -0
- package/lib/composer/ground.js +9 -0
- package/lib/composer/index.d.ts +19 -0
- package/lib/composer/index.js +19 -0
- package/lib/composer/layout.d.ts +106 -0
- package/lib/composer/layout.js +216 -0
- package/lib/composer/model.d.ts +298 -0
- package/lib/composer/model.js +441 -0
- package/lib/composer/overlap.d.ts +89 -0
- package/lib/composer/overlap.js +139 -0
- package/lib/composer/presentation.d.ts +123 -0
- package/lib/composer/presentation.js +256 -0
- package/lib/composer/reachability.d.ts +78 -0
- package/lib/composer/reachability.js +303 -0
- package/lib/composer/render-port.d.ts +293 -0
- package/lib/composer/render-port.js +172 -0
- package/lib/composer/terrain-runtime.d.ts +73 -0
- package/lib/composer/terrain-runtime.js +328 -0
- package/lib/composer/terrain.d.ts +43 -0
- package/lib/composer/terrain.js +49 -0
- package/lib/composer/world-document.d.ts +722 -0
- package/lib/composer/world-document.js +857 -0
- package/lib/composer/world-integration.d.ts +78 -0
- package/lib/composer/world-integration.js +452 -0
- package/lib/composer/world-package.d.ts +312 -0
- package/lib/composer/world-package.js +209 -0
- package/lib/contracts/asset.d.ts +270 -0
- package/lib/contracts/asset.js +1616 -0
- package/lib/contracts/breadth.d.ts +197 -0
- package/lib/contracts/breadth.js +631 -0
- package/lib/contracts/environment.d.ts +13 -0
- package/lib/contracts/environment.js +67 -0
- package/lib/contracts/index.d.ts +5 -0
- package/lib/contracts/index.js +5 -0
- package/lib/contracts/integration.d.ts +94 -0
- package/lib/contracts/integration.js +10 -0
- package/lib/contracts/requirements-migration.d.ts +61 -0
- package/lib/contracts/requirements-migration.js +401 -0
- package/lib/contracts/requirements.d.ts +815 -0
- package/lib/contracts/requirements.js +266 -0
- package/lib/contracts/semantic.d.ts +124 -0
- package/lib/contracts/semantic.js +421 -0
- package/lib/deform.d.ts +31 -0
- package/lib/deform.js +137 -0
- package/lib/deformation-normals.d.ts +3 -0
- package/lib/deformation-normals.js +72 -0
- package/lib/discovery/articulation-recipes.d.ts +6 -0
- package/lib/discovery/articulation-recipes.js +184 -0
- package/lib/discovery/catalog-schema.d.ts +175 -0
- package/lib/discovery/catalog-schema.js +118 -0
- package/lib/discovery/catalog.d.ts +25 -0
- package/lib/discovery/catalog.js +84 -0
- package/lib/discovery/construction-recipes.d.ts +7 -0
- package/lib/discovery/construction-recipes.js +236 -0
- package/lib/discovery/helper-contracts.d.ts +19 -0
- package/lib/discovery/helper-contracts.js +1940 -0
- package/lib/discovery/helper-specs.d.ts +40 -0
- package/lib/discovery/helper-specs.js +800 -0
- package/lib/discovery/index.d.ts +9 -0
- package/lib/discovery/index.js +20 -0
- package/lib/discovery/intents.d.ts +3 -0
- package/lib/discovery/intents.js +117 -0
- package/lib/discovery/lexical-index.d.ts +5 -0
- package/lib/discovery/lexical-index.js +67 -0
- package/lib/discovery/query-schema.d.ts +35 -0
- package/lib/discovery/query-schema.js +66 -0
- package/lib/discovery/recipes.d.ts +6 -0
- package/lib/discovery/recipes.js +191 -0
- package/lib/discovery/service.d.ts +57 -0
- package/lib/discovery/service.js +234 -0
- package/lib/discovery/shapes.d.ts +6 -0
- package/lib/discovery/shapes.js +65 -0
- package/lib/discovery/structural-recipes.d.ts +6 -0
- package/lib/discovery/structural-recipes.js +193 -0
- package/lib/discovery/surface-recipes.d.ts +7 -0
- package/lib/discovery/surface-recipes.js +124 -0
- package/lib/draw-diagnostics.d.ts +57 -0
- package/lib/draw-diagnostics.js +239 -0
- package/lib/edit-buffer.d.ts +86 -0
- package/lib/edit-buffer.js +99 -0
- package/lib/engine-identity.d.ts +44 -0
- package/lib/engine-identity.js +41 -0
- package/lib/evaluator/authoring-diagnostic.d.ts +38 -0
- package/lib/evaluator/authoring-diagnostic.js +128 -0
- package/lib/evaluator/handler.d.ts +14 -0
- package/lib/evaluator/handler.js +86 -0
- package/lib/evaluator/index.d.ts +4 -0
- package/lib/evaluator/index.js +4 -0
- package/lib/evaluator/isolation.d.ts +45 -0
- package/lib/evaluator/isolation.js +362 -0
- package/lib/evaluator/probe-invariants.d.ts +2 -0
- package/lib/evaluator/probe-invariants.js +7 -0
- package/lib/evaluator/probe-worker.d.ts +1 -0
- package/lib/evaluator/probe-worker.js +134 -0
- package/lib/evaluator/protocol.d.ts +105 -0
- package/lib/evaluator/protocol.js +512 -0
- package/lib/evaluator/source-check.d.ts +7 -0
- package/lib/evaluator/source-check.js +57 -0
- package/lib/evaluator/subprocess.d.ts +26 -0
- package/lib/evaluator/subprocess.js +212 -0
- package/lib/evaluator/transport-worker.d.mts +1 -0
- package/lib/evaluator/transport-worker.mjs +3 -0
- package/lib/evaluator/worker-urls.d.ts +6 -0
- package/lib/evaluator/worker-urls.js +12 -0
- package/lib/evaluator/worker.d.ts +1 -0
- package/lib/evaluator/worker.js +26 -0
- package/lib/exporter-node.d.ts +16 -0
- package/lib/exporter-node.js +58 -0
- package/lib/gears.d.ts +68 -0
- package/lib/gears.js +259 -0
- package/lib/geometry-budget.d.ts +15 -0
- package/lib/geometry-budget.js +36 -0
- package/lib/geometry-catalog.d.ts +5 -0
- package/lib/geometry-catalog.js +161 -0
- package/lib/geometry-export.d.ts +11 -0
- package/lib/geometry-export.js +160 -0
- package/lib/geometry.d.ts +46 -0
- package/lib/geometry.js +311 -0
- package/lib/gltf-io.d.ts +38 -0
- package/lib/gltf-io.js +95 -0
- package/lib/implicit.d.ts +20 -0
- package/lib/implicit.js +58 -0
- package/lib/index-policy.d.ts +13 -0
- package/lib/index-policy.js +41 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +5 -0
- package/lib/inspect.d.ts +76 -0
- package/lib/inspect.js +206 -0
- package/lib/kit.d.ts +90 -0
- package/lib/kit.js +459 -0
- package/lib/live-review-node.d.ts +70 -0
- package/lib/live-review-node.js +961 -0
- package/lib/live-review.d.ts +65 -0
- package/lib/live-review.js +1 -0
- package/lib/local-runtime.d.ts +25 -0
- package/lib/local-runtime.js +272 -0
- package/lib/lod-export.d.ts +39 -0
- package/lib/lod-export.js +102 -0
- package/lib/lod.d.ts +56 -0
- package/lib/lod.js +138 -0
- package/lib/material-library-node.d.ts +56 -0
- package/lib/material-library-node.js +402 -0
- package/lib/material-library.d.ts +731 -0
- package/lib/material-library.js +425 -0
- package/lib/material-metrics.d.ts +72 -0
- package/lib/material-metrics.js +276 -0
- package/lib/material-presets.d.ts +29 -0
- package/lib/material-presets.js +181 -0
- package/lib/material-recipe-prompt.d.ts +23 -0
- package/lib/material-recipe-prompt.js +72 -0
- package/lib/material-recipe-runtime.d.ts +31 -0
- package/lib/material-recipe-runtime.js +91 -0
- package/lib/material-recipes.d.ts +131 -0
- package/lib/material-recipes.js +543 -0
- package/lib/material-resources.d.ts +181 -0
- package/lib/material-resources.js +416 -0
- package/lib/material-texture-library.generated.d.ts +1311 -0
- package/lib/material-texture-library.generated.js +11308 -0
- package/lib/metrics.d.ts +98 -0
- package/lib/metrics.js +210 -0
- package/lib/node-visibility.d.ts +31 -0
- package/lib/node-visibility.js +105 -0
- package/lib/open-shell.d.ts +21 -0
- package/lib/open-shell.js +83 -0
- package/lib/ops.d.ts +197 -0
- package/lib/ops.js +630 -0
- package/lib/palette-snap.d.ts +74 -0
- package/lib/palette-snap.js +151 -0
- package/lib/palette.d.ts +75 -0
- package/lib/palette.js +273 -0
- package/lib/portable-material-runtime.d.ts +14 -0
- package/lib/portable-material-runtime.js +81 -0
- package/lib/primitives.d.ts +483 -0
- package/lib/primitives.js +1553 -0
- package/lib/procedural-material-v2.d.ts +189 -0
- package/lib/procedural-material-v2.js +452 -0
- package/lib/procedural-texture.d.ts +90 -0
- package/lib/procedural-texture.js +306 -0
- package/lib/profile.d.ts +190 -0
- package/lib/profile.js +366 -0
- package/lib/program-store-node.d.ts +14 -0
- package/lib/program-store-node.js +137 -0
- package/lib/program-store.d.ts +43 -0
- package/lib/program-store.js +89 -0
- package/lib/project-bundle-node.d.ts +15 -0
- package/lib/project-bundle-node.js +175 -0
- package/lib/project-bundle.d.ts +65 -0
- package/lib/project-bundle.js +322 -0
- package/lib/projects-node.d.ts +17 -0
- package/lib/projects-node.js +227 -0
- package/lib/projects.d.ts +312 -0
- package/lib/projects.js +216 -0
- package/lib/prompt-api.d.ts +32 -0
- package/lib/prompt-api.js +223 -0
- package/lib/qa/architecture-corpus.d.ts +31 -0
- package/lib/qa/architecture-corpus.js +438 -0
- package/lib/qa/architecture-repairs.d.ts +17 -0
- package/lib/qa/architecture-repairs.js +73 -0
- package/lib/qa/architecture.d.ts +56 -0
- package/lib/qa/architecture.js +985 -0
- package/lib/qa/benchmark-fixtures.d.ts +42 -0
- package/lib/qa/benchmark-fixtures.js +191 -0
- package/lib/qa/breadth-corpus.d.ts +17 -0
- package/lib/qa/breadth-corpus.js +125 -0
- package/lib/qa/breadth-evidence.d.ts +18 -0
- package/lib/qa/breadth-evidence.js +514 -0
- package/lib/qa/breadth-final.d.ts +46 -0
- package/lib/qa/breadth-final.js +359 -0
- package/lib/qa/breadth.d.ts +66 -0
- package/lib/qa/breadth.js +539 -0
- package/lib/qa/character-advisory.d.ts +7 -0
- package/lib/qa/character-advisory.js +488 -0
- package/lib/qa/character-repairs.d.ts +11 -0
- package/lib/qa/character-repairs.js +68 -0
- package/lib/qa/character-vehicle-corpus.d.ts +32 -0
- package/lib/qa/character-vehicle-corpus.js +525 -0
- package/lib/qa/character.d.ts +66 -0
- package/lib/qa/character.js +712 -0
- package/lib/qa/corpus.d.ts +185 -0
- package/lib/qa/corpus.js +396 -0
- package/lib/qa/environment.d.ts +44 -0
- package/lib/qa/environment.js +725 -0
- package/lib/qa/geometry-relations.d.ts +94 -0
- package/lib/qa/geometry-relations.js +552 -0
- package/lib/qa/gltf.d.ts +29 -0
- package/lib/qa/gltf.js +66 -0
- package/lib/qa/index.d.ts +32 -0
- package/lib/qa/index.js +34 -0
- package/lib/qa/lod.d.ts +14 -0
- package/lib/qa/lod.js +25 -0
- package/lib/qa/material.d.ts +5 -0
- package/lib/qa/material.js +223 -0
- package/lib/qa/part-connectivity.d.ts +73 -0
- package/lib/qa/part-connectivity.js +216 -0
- package/lib/qa/prop-environment-prompt.d.ts +6 -0
- package/lib/qa/prop-environment-prompt.js +43 -0
- package/lib/qa/prop-helper-policy.d.ts +37 -0
- package/lib/qa/prop-helper-policy.js +65 -0
- package/lib/qa/prop.d.ts +44 -0
- package/lib/qa/prop.js +702 -0
- package/lib/qa/reference-comparison.d.ts +183 -0
- package/lib/qa/reference-comparison.js +420 -0
- package/lib/qa/registry.d.ts +159 -0
- package/lib/qa/registry.js +406 -0
- package/lib/qa/requirements-applicability.d.ts +33 -0
- package/lib/qa/requirements-applicability.js +189 -0
- package/lib/qa/requirements-report.d.ts +38 -0
- package/lib/qa/requirements-report.js +202 -0
- package/lib/qa/requirements-run.d.ts +20 -0
- package/lib/qa/requirements-run.js +370 -0
- package/lib/qa/run.d.ts +54 -0
- package/lib/qa/run.js +240 -0
- package/lib/qa/self-intersection.d.ts +157 -0
- package/lib/qa/self-intersection.js +633 -0
- package/lib/qa/sweep.d.ts +4 -0
- package/lib/qa/sweep.js +65 -0
- package/lib/qa/types.d.ts +90 -0
- package/lib/qa/types.js +81 -0
- package/lib/qa/universal.d.ts +14 -0
- package/lib/qa/universal.js +398 -0
- package/lib/qa/vegetation-corpus.d.ts +18 -0
- package/lib/qa/vegetation-corpus.js +304 -0
- package/lib/qa/vegetation.d.ts +133 -0
- package/lib/qa/vegetation.js +933 -0
- package/lib/qa/vehicle-advisory.d.ts +8 -0
- package/lib/qa/vehicle-advisory.js +395 -0
- package/lib/qa/vehicle.d.ts +19 -0
- package/lib/qa/vehicle.js +594 -0
- package/lib/rebuild-options.d.ts +31 -0
- package/lib/rebuild-options.js +13 -0
- package/lib/render-capabilities.d.ts +25 -0
- package/lib/render-capabilities.js +100 -0
- package/lib/render-service-client.d.ts +59 -0
- package/lib/render-service-client.js +194 -0
- package/lib/render-service-host.d.ts +44 -0
- package/lib/render-service-host.js +236 -0
- package/lib/render-service-windows.d.ts +12 -0
- package/lib/render-service-windows.js +72 -0
- package/lib/render.d.ts +565 -0
- package/lib/render.js +1978 -0
- package/lib/requirements-assets.d.ts +6 -0
- package/lib/requirements-assets.js +33 -0
- package/lib/requirements-context.d.ts +1658 -0
- package/lib/requirements-context.js +126 -0
- package/lib/requirements-identity.d.ts +3 -0
- package/lib/requirements-identity.js +38 -0
- package/lib/requirements-json.d.ts +12 -0
- package/lib/requirements-json.js +58 -0
- package/lib/requirements-store.d.ts +42 -0
- package/lib/requirements-store.js +86 -0
- package/lib/requirements.d.ts +4 -0
- package/lib/requirements.js +4 -0
- package/lib/revision-comparison.d.ts +85 -0
- package/lib/revision-comparison.js +334 -0
- package/lib/rig-export.d.ts +5 -0
- package/lib/rig-export.js +19 -0
- package/lib/rigid-merge.d.ts +90 -0
- package/lib/rigid-merge.js +585 -0
- package/lib/runtime-identity.d.ts +20 -0
- package/lib/runtime-identity.js +193 -0
- package/lib/solids.d.ts +29 -0
- package/lib/solids.js +523 -0
- package/lib/source-bindings.d.ts +6 -0
- package/lib/source-bindings.js +96 -0
- package/lib/source-runtime-checks.d.ts +14 -0
- package/lib/source-runtime-checks.js +169 -0
- package/lib/sweep-analysis.d.ts +22 -0
- package/lib/sweep-analysis.js +109 -0
- package/lib/sweep.d.ts +34 -0
- package/lib/sweep.js +347 -0
- package/lib/texture-bake.d.ts +125 -0
- package/lib/texture-bake.js +395 -0
- package/lib/texture-contract.d.ts +3 -0
- package/lib/texture-contract.js +10 -0
- package/lib/texture-resolver.d.ts +22 -0
- package/lib/texture-resolver.js +28 -0
- package/lib/textures.d.ts +90 -0
- package/lib/textures.js +240 -0
- package/lib/tools/actions.d.ts +35 -0
- package/lib/tools/actions.js +69 -0
- package/lib/tools/capture-input.d.ts +373 -0
- package/lib/tools/capture-input.js +193 -0
- package/lib/tools/discovery.d.ts +3 -0
- package/lib/tools/discovery.js +177 -0
- package/lib/tools/materials.d.ts +29 -0
- package/lib/tools/materials.js +168 -0
- package/lib/tools/preview-fidelity.d.ts +6 -0
- package/lib/tools/preview-fidelity.js +23 -0
- package/lib/tools/program-artifacts.d.ts +30 -0
- package/lib/tools/program-artifacts.js +76 -0
- package/lib/tools/programs.d.ts +9 -0
- package/lib/tools/programs.js +151 -0
- package/lib/tools/projects.d.ts +27 -0
- package/lib/tools/projects.js +98 -0
- package/lib/tools/registry.d.ts +792 -0
- package/lib/tools/registry.js +2123 -0
- package/lib/tools/review-detail.d.ts +106 -0
- package/lib/tools/review-detail.js +740 -0
- package/lib/tools/review.d.ts +40 -0
- package/lib/tools/review.js +230 -0
- package/lib/tools/skill-resource.d.ts +8 -0
- package/lib/tools/skill-resource.js +1 -0
- package/lib/tools/workspace.d.ts +8 -0
- package/lib/tools/workspace.js +87 -0
- package/lib/user-data-extras.d.ts +40 -0
- package/lib/user-data-extras.js +158 -0
- package/lib/user-data-validation.d.ts +18 -0
- package/lib/user-data-validation.js +201 -0
- package/lib/uv-project.d.ts +14 -0
- package/lib/uv-project.js +145 -0
- package/lib/uv-shapes.d.ts +11 -0
- package/lib/uv-shapes.js +48 -0
- package/lib/uv.d.ts +39 -0
- package/lib/uv.js +216 -0
- package/lib/validation.d.ts +90 -0
- package/lib/validation.js +1099 -0
- package/lib/vehicle.d.ts +128 -0
- package/lib/vehicle.js +487 -0
- package/lib/views/annotate.d.ts +41 -0
- package/lib/views/annotate.js +131 -0
- package/lib/views/architecture.d.ts +22 -0
- package/lib/views/architecture.js +55 -0
- package/lib/views/background.d.ts +54 -0
- package/lib/views/background.js +65 -0
- package/lib/views/camera-capture.d.ts +15 -0
- package/lib/views/camera-capture.js +101 -0
- package/lib/views/camera.d.ts +106 -0
- package/lib/views/camera.js +488 -0
- package/lib/views/capture-cache.d.ts +48 -0
- package/lib/views/capture-cache.js +239 -0
- package/lib/views/capture-limits.d.ts +19 -0
- package/lib/views/capture-limits.js +61 -0
- package/lib/views/capture.d.ts +124 -0
- package/lib/views/capture.js +210 -0
- package/lib/views/character-capture.d.ts +20 -0
- package/lib/views/character-capture.js +180 -0
- package/lib/views/character.d.ts +64 -0
- package/lib/views/character.js +176 -0
- package/lib/views/diagnostic.d.ts +90 -0
- package/lib/views/diagnostic.js +627 -0
- package/lib/views/evidence-history.d.ts +13 -0
- package/lib/views/evidence-history.js +131 -0
- package/lib/views/glb.d.ts +36 -0
- package/lib/views/glb.js +524 -0
- package/lib/views/grid.d.ts +46 -0
- package/lib/views/grid.js +81 -0
- package/lib/views/index.d.ts +257 -0
- package/lib/views/index.js +624 -0
- package/lib/views/inspect.d.ts +110 -0
- package/lib/views/inspect.js +195 -0
- package/lib/views/lod.d.ts +30 -0
- package/lib/views/lod.js +79 -0
- package/lib/views/measurement.d.ts +47 -0
- package/lib/views/measurement.js +60 -0
- package/lib/views/part-placement.d.ts +25 -0
- package/lib/views/part-placement.js +26 -0
- package/lib/views/png.d.ts +23 -0
- package/lib/views/png.js +162 -0
- package/lib/views/port.d.ts +74 -0
- package/lib/views/port.js +250 -0
- package/lib/views/pose.d.ts +113 -0
- package/lib/views/pose.js +433 -0
- package/lib/views/raster.d.ts +164 -0
- package/lib/views/raster.js +508 -0
- package/lib/views/renderer-id.d.ts +11 -0
- package/lib/views/renderer-id.js +29 -0
- package/lib/views/scene-raster.d.ts +41 -0
- package/lib/views/scene-raster.js +84 -0
- package/lib/views/surface-distance.d.ts +51 -0
- package/lib/views/surface-distance.js +343 -0
- package/lib/views/vehicle.d.ts +57 -0
- package/lib/views/vehicle.js +288 -0
- package/lib/wall-panels.d.ts +38 -0
- package/lib/wall-panels.js +99 -0
- package/lib/widget-transfer.d.ts +12 -0
- package/lib/widget-transfer.js +117 -0
- package/lib/workspace-location.d.ts +6 -0
- package/lib/workspace-location.js +16 -0
- package/lib/workspace-node.d.ts +15 -0
- package/lib/workspace-node.js +74 -0
- package/lib/workspace.d.ts +26 -0
- package/lib/workspace.js +22 -0
- package/lib/written-nodes.d.ts +10 -0
- package/lib/written-nodes.js +32 -0
- package/package.json +385 -4
- package/plugin.json +16 -0
- package/plugins/kiln-engine/.claude-plugin/plugin.json +18 -0
- package/plugins/kiln-engine/LICENSE +21 -0
- package/plugins/kiln-engine/README.md +25 -0
- package/plugins/kiln-engine/package-provenance.json +15 -0
- package/plugins/kiln-engine/plugin.json +38 -0
- package/plugins/kiln-engine/runtime.json +4 -0
- package/plugins/kiln-engine/scripts/setup-workspace.mjs +337 -0
- package/plugins/kiln-engine/skills/kiln-setup-workspace/SKILL.md +108 -0
- package/plugins/kiln-engine/skills/kiln-setup-workspace/references/plugin-install.md +66 -0
- package/render-service/README.md +139 -0
- package/render-service/package-lock.json +72 -0
- package/render-service/package.json +22 -0
- package/render-service/src/backdrops.mjs +26 -0
- package/render-service/src/bind-policy.mjs +80 -0
- package/render-service/src/build-identity.mjs +83 -0
- package/render-service/src/cache-identity.mjs +65 -0
- package/render-service/src/contract.mjs +494 -0
- package/render-service/src/display-output.mjs +18 -0
- package/render-service/src/display-transform.mjs +192 -0
- package/render-service/src/framing.mjs +114 -0
- package/render-service/src/glb-input.mjs +259 -0
- package/render-service/src/gpu.mjs +101 -0
- package/render-service/src/health-contract.mjs +40 -0
- package/render-service/src/instance.mjs +146 -0
- package/render-service/src/node-visibility.mjs +49 -0
- package/render-service/src/png-input.mjs +77 -0
- package/render-service/src/presentation-presets.mjs +216 -0
- package/render-service/src/readback.mjs +16 -0
- package/render-service/src/register-hooks.mjs +2 -0
- package/render-service/src/render-queue.mjs +144 -0
- package/render-service/src/renderer.mjs +473 -0
- package/render-service/src/request-limits.mjs +72 -0
- package/render-service/src/review-tone-mapping.mjs +55 -0
- package/render-service/src/server.mjs +387 -0
- package/render-service/src/three-alias-hooks.mjs +6 -0
- package/scripts/create-workspace.mjs +808 -0
- package/scripts/package-plugin.mjs +67 -0
- package/skills/kiln-author-asset/SKILL.md +104 -0
- package/skills/kiln-author-asset/references/camera-cli.md +33 -0
- package/skills/kiln-author-asset/references/camera-recipes.md +73 -0
- package/skills/kiln-author-asset/references/export-profiles.md +216 -0
- package/skills/kiln-author-asset/references/geometry-recipes.md +329 -0
- package/skills/kiln-author-asset/references/program-contract.md +44 -0
- package/skills/kiln-author-asset/references/projects-and-materials.md +158 -0
- package/skills/kiln-author-asset/references/reusable-frame.kiln.js +32 -0
- package/skills/kiln-batch-dispatch/SKILL.md +22 -0
- package/skills/kiln-batch-dispatch/references/clean-room-evaluation.md +35 -0
- package/skills/kiln-compose-scene/SKILL.md +38 -0
- package/skills/kiln-compose-scene/references/composition-api.md +29 -0
- package/skills/kiln-compose-scene/references/runtime-scenes.md +363 -0
- package/skills/kiln-qa-asset/SKILL.md +99 -0
- package/skills/kiln-qa-asset/references/engine-handoff.md +246 -0
- package/skills/kiln-qa-asset/references/integration-checks.md +96 -0
- package/skills/kiln-refine-asset/SKILL.md +136 -0
- package/skills/kiln-refine-asset/references/revision-and-views.md +205 -0
- package/skills/kiln-refine-asset/references/revision-cli.md +39 -0
- package/skills/kiln-setup-workspace/SKILL.md +108 -0
- package/skills/kiln-setup-workspace/references/plugin-install.md +66 -0
- package/src/agent/call-budget.ts +106 -0
- package/src/agent/compaction.ts +197 -0
- package/src/agent/concurrency.ts +30 -0
- package/src/agent/diff.ts +141 -0
- package/src/agent/generate.ts +448 -0
- package/src/agent/hooks.ts +204 -0
- package/src/agent/index.ts +114 -0
- package/src/agent/native-prompt.ts +51 -0
- package/src/agent/native-workflow.ts +33 -0
- package/src/agent/providers.ts +529 -0
- package/src/agent/run.ts +356 -0
- package/src/agent/skill-resources.ts +198 -0
- package/src/agent/split-tool-result-images.ts +80 -0
- package/src/agent/stream-start.ts +61 -0
- package/src/agent/tools.ts +113 -0
- package/src/agent/view-render-timeout.ts +110 -0
- package/src/animation-cli.ts +251 -0
- package/src/animation-cubic.ts +57 -0
- package/src/animation-spline.ts +183 -0
- package/src/architecture.ts +871 -0
- package/src/arena/adaptive.ts +119 -0
- package/src/arena/bradley-terry.ts +221 -0
- package/src/arena/index.ts +21 -0
- package/src/assembly-transform.ts +34 -0
- package/src/assembly.ts +762 -0
- package/src/asset-catalog.ts +30 -0
- package/src/asset-cli.ts +505 -0
- package/src/asset-export.ts +141 -0
- package/src/asset-materials-node.ts +78 -0
- package/src/asset-viewer.ts +160 -0
- package/src/asset-widget-uri.ts +9 -0
- package/src/asset-widget.ts +38 -0
- package/src/assets-node.ts +412 -0
- package/src/assets-resources.ts +137 -0
- package/src/assets.ts +252 -0
- package/src/atomic-directory.ts +45 -0
- package/src/authoring-style.ts +49 -0
- package/src/breadth-prompt.ts +79 -0
- package/src/build-cache-node.ts +99 -0
- package/src/build-cache.ts +253 -0
- package/src/character.ts +776 -0
- package/src/cli-json.ts +29 -0
- package/src/cli-output.ts +135 -0
- package/src/cli-render-mode.ts +270 -0
- package/src/cli.ts +809 -0
- package/src/community-exporter.ts +268 -0
- package/src/composer/agent/compaction.ts +146 -0
- package/src/composer/agent/index.ts +41 -0
- package/src/composer/agent/prompt.ts +126 -0
- package/src/composer/agent/run.ts +317 -0
- package/src/composer/agent/tools.ts +847 -0
- package/src/composer/agent/world-run.ts +421 -0
- package/src/composer/agent/world-tools.ts +411 -0
- package/src/composer/collision.ts +448 -0
- package/src/composer/contract-utils.ts +52 -0
- package/src/composer/dsl.ts +196 -0
- package/src/composer/ground.ts +27 -0
- package/src/composer/index.ts +19 -0
- package/src/composer/layout.ts +357 -0
- package/src/composer/model.ts +688 -0
- package/src/composer/overlap.ts +220 -0
- package/src/composer/presentation.ts +309 -0
- package/src/composer/reachability.ts +407 -0
- package/src/composer/render-port.ts +516 -0
- package/src/composer/terrain-runtime.ts +415 -0
- package/src/composer/terrain.ts +53 -0
- package/src/composer/world-document.ts +1019 -0
- package/src/composer/world-integration.ts +589 -0
- package/src/composer/world-package.ts +255 -0
- package/src/contracts/asset.ts +2030 -0
- package/src/contracts/breadth.ts +888 -0
- package/src/contracts/environment.ts +81 -0
- package/src/contracts/index.ts +5 -0
- package/src/contracts/integration.ts +100 -0
- package/src/contracts/requirements-migration.ts +536 -0
- package/src/contracts/requirements.ts +357 -0
- package/src/contracts/semantic.ts +544 -0
- package/src/deform.ts +215 -0
- package/src/deformation-normals.ts +84 -0
- package/src/direct-entry.ts +28 -0
- package/src/discovery/articulation-recipes.ts +190 -0
- package/src/discovery/catalog-schema.ts +125 -0
- package/src/discovery/catalog.ts +88 -0
- package/src/discovery/construction-recipes.ts +243 -0
- package/src/discovery/helper-contracts.ts +2388 -0
- package/src/discovery/helper-specs.ts +1046 -0
- package/src/discovery/index.ts +36 -0
- package/src/discovery/intents.ts +120 -0
- package/src/discovery/lexical-index.ts +72 -0
- package/src/discovery/query-schema.ts +71 -0
- package/src/discovery/recipes.ts +215 -0
- package/src/discovery/service.ts +329 -0
- package/src/discovery/shapes.ts +120 -0
- package/src/discovery/structural-recipes.ts +199 -0
- package/src/discovery/surface-recipes.ts +130 -0
- package/src/discovery-cli.ts +106 -0
- package/src/draw-diagnostics.ts +313 -0
- package/src/edit-buffer.ts +134 -0
- package/src/edit-cli.ts +125 -0
- package/src/engine-identity.ts +50 -0
- package/src/evaluator/authoring-diagnostic.ts +168 -0
- package/src/evaluator/handler.ts +114 -0
- package/src/evaluator/index.ts +50 -0
- package/src/evaluator/isolation.ts +454 -0
- package/src/evaluator/probe-invariants.ts +9 -0
- package/src/evaluator/probe-worker.ts +158 -0
- package/src/evaluator/protocol.ts +701 -0
- package/src/evaluator/source-check.ts +64 -0
- package/src/evaluator/subprocess.ts +294 -0
- package/src/evaluator/transport-worker.mjs +8 -0
- package/src/evaluator/worker-urls.ts +16 -0
- package/src/evaluator/worker.ts +26 -0
- package/src/experiments/geometry-acceptance.ts +278 -0
- package/src/experiments/geometry-frontier.ts +181 -0
- package/src/experiments/program-aliases.ts +96 -0
- package/src/experiments/run-w6-material-vegetation.ts +7 -0
- package/src/experiments/run-w7-vegetation-lod.ts +6 -0
- package/src/experiments/w6-material-vegetation.ts +772 -0
- package/src/experiments/w7-vegetation-lod.ts +335 -0
- package/src/exporter-node.ts +68 -0
- package/src/gears.ts +334 -0
- package/src/generated/mcp-manifest.json +2050 -0
- package/src/geometry-budget.ts +50 -0
- package/src/geometry-catalog.ts +215 -0
- package/src/geometry-export.ts +193 -0
- package/src/geometry.ts +379 -0
- package/src/gltf-io.ts +129 -0
- package/src/gltf-validator-shims.d.ts +12 -0
- package/src/implicit.ts +106 -0
- package/src/index-policy.ts +52 -0
- package/src/index.ts +5 -0
- package/src/inspect-cli.ts +198 -0
- package/src/inspect.ts +290 -0
- package/src/kit.ts +547 -0
- package/src/live-review-node.ts +1011 -0
- package/src/live-review.ts +55 -0
- package/src/local-runtime.ts +336 -0
- package/src/lod-export.ts +120 -0
- package/src/lod.ts +192 -0
- package/src/loopback.ts +6 -0
- package/src/material-library-node.ts +488 -0
- package/src/material-library.ts +481 -0
- package/src/material-metrics.ts +392 -0
- package/src/material-presets.ts +207 -0
- package/src/material-recipe-prompt.ts +99 -0
- package/src/material-recipe-runtime.ts +162 -0
- package/src/material-recipes.ts +748 -0
- package/src/material-resources.ts +640 -0
- package/src/material-texture-library.generated.ts +11408 -0
- package/src/mcp-core.ts +437 -0
- package/src/mcp-engine.ts +383 -0
- package/src/mcp-manifest.ts +104 -0
- package/src/mcp-server.ts +118 -0
- package/src/metrics.ts +277 -0
- package/src/migration-cli.ts +105 -0
- package/src/migration-rebuild.ts +265 -0
- package/src/node-visibility.ts +116 -0
- package/src/open-shell.ts +104 -0
- package/src/ops.ts +751 -0
- package/src/palette-snap.ts +209 -0
- package/src/palette.ts +307 -0
- package/src/portable-material-runtime.ts +109 -0
- package/src/primitives.ts +2299 -0
- package/src/procedural-material-v2.ts +720 -0
- package/src/procedural-texture.ts +427 -0
- package/src/profile.ts +485 -0
- package/src/program-store-node.ts +138 -0
- package/src/program-store.ts +116 -0
- package/src/project-bundle-node.ts +220 -0
- package/src/project-bundle.ts +392 -0
- package/src/project-cli.ts +248 -0
- package/src/projects-node.ts +270 -0
- package/src/projects.ts +274 -0
- package/src/prompt-api.ts +231 -0
- package/src/qa/architecture-corpus.ts +828 -0
- package/src/qa/architecture-repairs.ts +92 -0
- package/src/qa/architecture.ts +1358 -0
- package/src/qa/benchmark-fixtures.ts +441 -0
- package/src/qa/breadth-corpus.ts +168 -0
- package/src/qa/breadth-evidence.ts +595 -0
- package/src/qa/breadth-final.ts +453 -0
- package/src/qa/breadth.ts +690 -0
- package/src/qa/character-advisory.ts +596 -0
- package/src/qa/character-repairs.ts +185 -0
- package/src/qa/character-vehicle-corpus.ts +802 -0
- package/src/qa/character.ts +998 -0
- package/src/qa/corpus.ts +499 -0
- package/src/qa/environment.ts +903 -0
- package/src/qa/geometry-relations.ts +843 -0
- package/src/qa/gltf.ts +103 -0
- package/src/qa/index.ts +34 -0
- package/src/qa/lod.ts +28 -0
- package/src/qa/material.ts +302 -0
- package/src/qa/part-connectivity.ts +252 -0
- package/src/qa/prop-environment-prompt.ts +58 -0
- package/src/qa/prop-helper-policy.ts +118 -0
- package/src/qa/prop.ts +828 -0
- package/src/qa/reference-comparison.ts +495 -0
- package/src/qa/registry.ts +604 -0
- package/src/qa/requirements-applicability.ts +241 -0
- package/src/qa/requirements-report.ts +280 -0
- package/src/qa/requirements-run.ts +470 -0
- package/src/qa/run.ts +329 -0
- package/src/qa/self-intersection.ts +741 -0
- package/src/qa/sweep.ts +68 -0
- package/src/qa/types.ts +187 -0
- package/src/qa/universal.ts +506 -0
- package/src/qa/vegetation-corpus.ts +404 -0
- package/src/qa/vegetation.ts +1174 -0
- package/src/qa/vehicle-advisory.ts +468 -0
- package/src/qa/vehicle.ts +756 -0
- package/src/rebuild-options.ts +16 -0
- package/src/render-capabilities.ts +140 -0
- package/src/render-service-client.ts +297 -0
- package/src/render-service-host.ts +278 -0
- package/src/render-service-windows.ts +80 -0
- package/src/render.ts +2748 -0
- package/src/requirements-assets.ts +53 -0
- package/src/requirements-context.ts +170 -0
- package/src/requirements-file.ts +10 -0
- package/src/requirements-identity.ts +43 -0
- package/src/requirements-json.ts +65 -0
- package/src/requirements-store.ts +150 -0
- package/src/requirements.ts +4 -0
- package/src/review-cli.ts +81 -0
- package/src/revision-comparison.ts +425 -0
- package/src/rig-export.ts +29 -0
- package/src/rigid-merge.ts +691 -0
- package/src/runtime-identity.ts +207 -0
- package/src/runtime-support.mjs +20 -0
- package/src/service-cli.ts +210 -0
- package/src/solids.ts +650 -0
- package/src/source-bindings.ts +90 -0
- package/src/source-runtime-checks.ts +189 -0
- package/src/sweep-analysis.ts +168 -0
- package/src/sweep.ts +482 -0
- package/src/texture-bake.ts +526 -0
- package/src/texture-contract.ts +12 -0
- package/src/texture-resolver.ts +61 -0
- package/src/textures.ts +345 -0
- package/src/tools/actions.ts +124 -0
- package/src/tools/capture-input.ts +233 -0
- package/src/tools/discovery.ts +194 -0
- package/src/tools/materials.ts +206 -0
- package/src/tools/preview-fidelity.ts +31 -0
- package/src/tools/program-artifacts.ts +107 -0
- package/src/tools/programs.ts +190 -0
- package/src/tools/projects.ts +141 -0
- package/src/tools/registry.ts +3111 -0
- package/src/tools/review-detail.ts +788 -0
- package/src/tools/review.ts +269 -0
- package/src/tools/skill-resource.ts +9 -0
- package/src/tools/workspace.ts +112 -0
- package/src/user-data-extras.ts +181 -0
- package/src/user-data-validation.ts +211 -0
- package/src/uv-project.ts +185 -0
- package/src/uv-shapes.ts +63 -0
- package/src/uv.ts +301 -0
- package/src/validation.ts +1257 -0
- package/src/vegetation-prompt.ts +109 -0
- package/src/vehicle.ts +742 -0
- package/src/viewer/app.ts +666 -0
- package/src/viewer/attribution.ts +17 -0
- package/src/viewer/camera-state.ts +45 -0
- package/src/viewer/chat-app.ts +221 -0
- package/src/viewer/chat-download.ts +53 -0
- package/src/viewer/dashboard.ts +59 -0
- package/src/viewer/deep-link.ts +34 -0
- package/src/viewer/dom.ts +63 -0
- package/src/viewer/framing.ts +55 -0
- package/src/viewer/library-state.ts +34 -0
- package/src/viewer/live-panel.ts +742 -0
- package/src/viewer/live-state.ts +99 -0
- package/src/viewer/load-guard.ts +10 -0
- package/src/viewer/lod-control.ts +98 -0
- package/src/viewer/lod.ts +172 -0
- package/src/viewer/material-preset-form.ts +34 -0
- package/src/viewer/materials-panel.ts +335 -0
- package/src/viewer/membership-panel.ts +122 -0
- package/src/viewer/navigation.ts +9 -0
- package/src/viewer/performance-control.ts +75 -0
- package/src/viewer/performance.ts +61 -0
- package/src/viewer/project-editor.ts +37 -0
- package/src/viewer/project-membership.ts +20 -0
- package/src/viewer/projects-panel.ts +374 -0
- package/src/viewer/scene.ts +426 -0
- package/src/viewer/visibility.ts +73 -0
- package/src/views/annotate.ts +138 -0
- package/src/views/architecture.ts +77 -0
- package/src/views/background.ts +87 -0
- package/src/views/camera-capture.ts +143 -0
- package/src/views/camera.ts +622 -0
- package/src/views/capture-cache.ts +272 -0
- package/src/views/capture-limits.ts +73 -0
- package/src/views/capture.ts +300 -0
- package/src/views/character-capture.ts +279 -0
- package/src/views/character.ts +267 -0
- package/src/views/diagnostic.ts +853 -0
- package/src/views/evidence-history.ts +166 -0
- package/src/views/glb.ts +747 -0
- package/src/views/grid.ts +118 -0
- package/src/views/index.ts +1071 -0
- package/src/views/inspect.ts +296 -0
- package/src/views/lod.ts +117 -0
- package/src/views/measurement.ts +69 -0
- package/src/views/part-placement.ts +50 -0
- package/src/views/png.ts +175 -0
- package/src/views/port.ts +335 -0
- package/src/views/pose.ts +541 -0
- package/src/views/raster.ts +627 -0
- package/src/views/renderer-id.ts +31 -0
- package/src/views/scene-raster.ts +139 -0
- package/src/views/surface-distance.ts +403 -0
- package/src/views/vehicle.ts +431 -0
- package/src/wall-panels.ts +127 -0
- package/src/widget-transfer.ts +115 -0
- package/src/workspace-cli.ts +41 -0
- package/src/workspace-http.ts +219 -0
- package/src/workspace-location.ts +20 -0
- package/src/workspace-node.ts +91 -0
- package/src/workspace.ts +43 -0
- package/src/written-nodes.ts +39 -0
- package/src/xatlasjs-shims.d.ts +16 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,2579 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Changes to `@instruktlabs/kiln` (previously the private `@kiln/engine` package).
|
|
4
|
+
Source releases and installable package publication are separate milestones.
|
|
5
|
+
Published versions and tags are recorded by the npm registry; changing this file
|
|
6
|
+
does not publish a package.
|
|
7
|
+
|
|
8
|
+
## 1.0.0
|
|
9
|
+
|
|
10
|
+
Changes since the 0.10.0 tagged package release, qualified first through the public
|
|
11
|
+
`1.0.0-rc.1` prerelease. Promotion of the stable archive to npm `latest` requires
|
|
12
|
+
the separate release gates in [the runbook](docs/releasing.md).
|
|
13
|
+
Hosted deployment and vendor directory acceptance remain separate milestones.
|
|
14
|
+
|
|
15
|
+
- **Breaking:** the npm identity is now `@instruktlabs/kiln`, with compiled ESM and
|
|
16
|
+
TypeScript declarations for its public subpaths. The root is a library entrypoint;
|
|
17
|
+
use the `kiln` executable for the CLI. `kiln-mcp` starts the stdio MCP server.
|
|
18
|
+
- Consumer archives contain the maintained installation/API/workflow documentation;
|
|
19
|
+
historical plans, reviews and model traces remain in the repository. Current
|
|
20
|
+
repository links and package publisher metadata point to Instrukt Labs.
|
|
21
|
+
- Installed isolated evaluation resolves compiled workers and readiness probes
|
|
22
|
+
without a TypeScript loader. Host isolation still requires its own readiness proof.
|
|
23
|
+
- The stdio executable cancels pending engine warmup when its client disconnects;
|
|
24
|
+
a tool-list-only session no longer starts unused engine work after closing stdin.
|
|
25
|
+
- Isolated evaluation explicitly requires a user namespace before disabling nested
|
|
26
|
+
namespaces, satisfying Bubblewrap's launch precondition. Unsupported hosts still
|
|
27
|
+
fail closed before source execution.
|
|
28
|
+
- Windows asset saves retry transient directory-rename denials within a bounded
|
|
29
|
+
delay, preserving atomic publication and existing immutable revisions.
|
|
30
|
+
- Source restoration, MCP source resources, reviewed saves and CLI rebuild
|
|
31
|
+
observations preserve an authored UTF-8 BOM instead of silently changing the
|
|
32
|
+
source and its program reference. Invalid source UTF-8 is rejected on those reads.
|
|
33
|
+
- Custom asset-library hosts can reuse the canonical saved-material resolver
|
|
34
|
+
through `@instruktlabs/kiln/assets/node`.
|
|
35
|
+
- The `kiln-engine` local plugin uses the Instrukt Labs marketplace and installs a
|
|
36
|
+
pinned engine outside its disposable cache. It registers setup only; managed
|
|
37
|
+
workspaces own the authoring skills and one MCP server. Upgrades preserve stores
|
|
38
|
+
and refuse conflicts. The npm archive includes the small bundle and both catalogs.
|
|
39
|
+
Replacing an older `kiln@kiln` installation requires the explicit plugin migration;
|
|
40
|
+
public directory submission and hosted access remain separate release work.
|
|
41
|
+
|
|
42
|
+
- Blind-run receipts recognize OpenCode's recorded code-mode MCP calls and AGY's
|
|
43
|
+
generic MCP dispatcher without inferring execution from source or output text.
|
|
44
|
+
Setup and authoring guidance now covers waiting for independent authors, checking
|
|
45
|
+
sloping panel fit, retaining repeated parts during edits and saving child revisions
|
|
46
|
+
before exporting. The eight-asset campaign records its incomplete handoffs and
|
|
47
|
+
visual defects separately from valid exports.
|
|
48
|
+
|
|
49
|
+
- **Breaking (v1 candidate):** `optimize: 'full'` replaces flatten/join with rigid-group
|
|
50
|
+
merging. Its rigid-merge pass preserves node names, hierarchy and transforms, including animated targets,
|
|
51
|
+
named joint pivots, semantic nodes, composition placements and LOD levels. Ordinary
|
|
52
|
+
named mesh nodes can become empty or hold merged geometry. When geometry must remain
|
|
53
|
+
on every named part, use `optimize: 'off'` or `'palette'` with `instance: 'off'`;
|
|
54
|
+
the separate GPU-instancing pass can remove named instance nodes. Shared-buffer expansion is limited
|
|
55
|
+
to 4 KiB per saved draw, and merged buckets split at 65,534 vertices. Results expose
|
|
56
|
+
boundary, lock and rejection diagnostics. New builds record `rigid-v1`; exact
|
|
57
|
+
rebuilds of older unversioned full-mode revisions require their original engine
|
|
58
|
+
or an explicit new authoring revision. Original saved GLBs remain exportable.
|
|
59
|
+
- ORM packing isolates shared images per metallic-roughness/occlusion pair. Materials
|
|
60
|
+
with different AO maps and consumers in other texture slots retain their original
|
|
61
|
+
pixels, UVs and samplers; identical packing pairs reuse the packed image.
|
|
62
|
+
- Scene browser tools share portable executable discovery and clean up temporary
|
|
63
|
+
profiles on launch failure and close. The normal portable scene gate includes
|
|
64
|
+
script tests, and the static server identifies WebP images correctly.
|
|
65
|
+
- Cloudflare Pages deployment has a portable Node preflight that verifies the exact
|
|
66
|
+
launch-mode artifact inventory, sizes and hashes against a clean checkout before
|
|
67
|
+
upload. The PowerShell entry delegates to the same implementation.
|
|
68
|
+
- Inspection and export summaries add bounded per-anchor draw counts, a qualified
|
|
69
|
+
rigid-merge estimate, and sampled mirrored-tangent/coplanar-part observations.
|
|
70
|
+
Compact render output and tool input schemas stay unchanged; estimates and flags
|
|
71
|
+
are advisory, not GPU timings or QA acceptance.
|
|
72
|
+
- Compatible dependency updates include glTF Transform 4.5.1, manifold 3.5.4,
|
|
73
|
+
MCP client/server 2.3.0, Strands 1.19.0 with the compatible AI SDK 6/provider 3
|
|
74
|
+
family, image libraries and tooling. Site/scenes use Vite 8.3.2. Maintainer pins
|
|
75
|
+
move to Node 22.23.3/npm 12.2.0, retaining Bun 1.4.2 and consumer Node compatibility.
|
|
76
|
+
- The exact-input scene release gate verifies public pack hashes and cannot pass
|
|
77
|
+
through missing-fixture skips. Shadow caches observe morph weights, Farm's economy
|
|
78
|
+
tier retains its trailer casters, and Golden Gate reflections exclude dynamic
|
|
79
|
+
traffic/player/fog while preserving vegetation; diagnostic fog hiding persists.
|
|
80
|
+
|
|
81
|
+
- The scenes' dependency pin check resolves the engine, site and render service
|
|
82
|
+
from the integrated checkout instead of hard-coded Windows worktrees. It now
|
|
83
|
+
runs on the Linux hub and relocated checkouts; a filesystem regression test
|
|
84
|
+
verifies collection and detection of an engine pin mismatch. Contributor and
|
|
85
|
+
Troy resume instructions name the current validation and workspace setup commands.
|
|
86
|
+
- The kit pass (`applyKitContract`, `packKitGlb`) no longer folds an occlusion map into the
|
|
87
|
+
metallic-roughness image when the two are read through different UV sets or
|
|
88
|
+
`KHR_texture_transform` values. It used to point the occlusion slot at the
|
|
89
|
+
metallic-roughness UV set as well, so a baked AO map on `TEXCOORD_1` was sampled through
|
|
90
|
+
`TEXCOORD_0`. Such a material keeps its separate occlusion image and UV set, and the
|
|
91
|
+
summary's new `ormSkipped` names the material and the reason; a matching pair packs as
|
|
92
|
+
before, and packing no longer rewrites the occlusion slot's UV set.
|
|
93
|
+
- `src/render.ts` and `src/__tests__/optimize.test.ts` no longer cite
|
|
94
|
+
`docs/kiln-material-consolidation-cycle.md`, which exists on no branch; the `OptimizeMode`
|
|
95
|
+
comment states the rule in place.
|
|
96
|
+
- `docs/runtime.md` documents `KILN_BAKE_OPTIMIZE` and `KILN_BAKE_INSTANCE`: their values,
|
|
97
|
+
that they only set the default for a render that omits `optimize` or `instance`, that the
|
|
98
|
+
MCP and CLI tools pin `optimize: 'off'` (so only `KILN_BAKE_INSTANCE` reaches their GLBs),
|
|
99
|
+
which library renders take the variables, and that a saved revision rebuilds with the
|
|
100
|
+
options its manifest recorded. No behaviour changes.
|
|
101
|
+
|
|
102
|
+
## 0.10.0
|
|
103
|
+
|
|
104
|
+
**Protocol revision 2026-07-28, and a server that answers before it loads.** The v1
|
|
105
|
+
readiness cycle ([plan](docs/plans/2026-10-01-v1-readiness-cycle.md)) measures Kiln under
|
|
106
|
+
Claude Code, Codex, OpenCode and Antigravity and fixes what the sessions show. Entries
|
|
107
|
+
marked **Breaking** change what a client or an embedder observes.
|
|
108
|
+
|
|
109
|
+
### MCP transport
|
|
110
|
+
|
|
111
|
+
- **The stdio server serves protocol revision 2026-07-28 beside the 2025 handshake
|
|
112
|
+
revisions.** `@modelcontextprotocol/server` and `client` move to 2.2.0 and `ext-apps` to
|
|
113
|
+
2.0.3. A 2026-07-28 client sends `server/discover` or any request carrying the per-request
|
|
114
|
+
`_meta` envelope and needs no handshake; a 2025-11-25 or 2025-06-18 client sends
|
|
115
|
+
`initialize` as before. Every 2026-07-28 result carries `resultType` and the server
|
|
116
|
+
identity; `server/discover`, `tools/list`, `resources/list`, `resources/templates/list` and
|
|
117
|
+
the viewer page read are `public` with a one-day `ttlMs`, while asset and project reads
|
|
118
|
+
stay `private` with `ttlMs: 0`.
|
|
119
|
+
- **Breaking:** a request that carries neither a protocol version nor a preceding
|
|
120
|
+
`initialize` is answered `-32602` with both ways in, instead of being served as a 2025
|
|
121
|
+
session. `listChanged` is no longer advertised for tools or resources (the lists are
|
|
122
|
+
fixed for a build) and `subscriptions/listen` acknowledges no list-changed
|
|
123
|
+
notifications. Advertised schemas no longer carry `$schema`.
|
|
124
|
+
- **The entry is thin.** `dist/mcp-server.mjs` bundles the protocol library and a generated
|
|
125
|
+
manifest of the definitions (`src/generated/mcp-manifest.json`, regenerated by the build
|
|
126
|
+
and by `bun run mcp:manifest`), answers `initialize`, `server/discover` and `tools/list`
|
|
127
|
+
from it (229 ms after process start in the startup test on the maintainer's PC, against
|
|
128
|
+
1.1 to 1.7 s before), and loads `dist/mcp-engine.mjs` on the first call that needs the
|
|
129
|
+
engine, warming it once the harness holds the tool list. **Breaking** for hand-wired
|
|
130
|
+
installs that copied the one file: both bundles must stay together.
|
|
131
|
+
- **Breaking:** a configuration problem no longer kills the server at startup. A stale
|
|
132
|
+
workspace, an invalid `KILN_RENDER` or a missing engine bundle come back as the first tool
|
|
133
|
+
result, naming the next step and no local path; the next call tries again, so a workspace
|
|
134
|
+
repaired while the harness is open needs no restart. A wrong command-line option and an
|
|
135
|
+
unreadable or legacy `--requirements` file still exit 1 before the protocol starts.
|
|
136
|
+
- **Breaking** for embedders: `createKilnMcpServer`, `kilnMcpToolDefs` and `runTool` moved
|
|
137
|
+
from `src/mcp-server.ts` to `src/mcp-engine.ts`, and `createKilnMcpServer` returns the
|
|
138
|
+
low-level `Server`; `MCP_SERVER_NAME`, `MCP_SERVER_VERSION` and `MCP_SERVER_INSTRUCTIONS`
|
|
139
|
+
live in `src/mcp-core.ts`. `src/requirements-json.ts` reads a host binding file without
|
|
140
|
+
zod; `readHostRequirementsFile` validates on top of it as before.
|
|
141
|
+
|
|
142
|
+
### Tool surface
|
|
143
|
+
|
|
144
|
+
One versioned batch: tool definitions are prompt-cached, so every schema and description
|
|
145
|
+
change lands together. Measured on the packaged manifest: the seventeen advertised
|
|
146
|
+
definitions 39,603 characters as JSON (74,649 before), every input schema within 5,000
|
|
147
|
+
bytes (four were over, the largest 18,788), input schemas 26,475 bytes in all (61,598),
|
|
148
|
+
`src/generated/mcp-manifest.json` 72,659 characters (205,917).
|
|
149
|
+
|
|
150
|
+
- **Breaking:** `kiln_project`, `kiln_material` and `kiln_review` are one flat object each
|
|
151
|
+
with an `action` enum instead of a root `oneOf` (Claude Code dropped all three). Every
|
|
152
|
+
other field is optional in the schema; the server checks what each action needs and names
|
|
153
|
+
the missing fields. The nested `draft`, `patch` and `payload` records are opaque in the
|
|
154
|
+
schema and validated when the action runs; `kiln_discover({ ids: ['shape:project-draft'] })`
|
|
155
|
+
(and `shape:project-patch`, `shape:material-draft`, `shape:material-import`) returns the
|
|
156
|
+
full JSON Schema through the new Discovery kind `shape`. `kiln_project` offers `export`
|
|
157
|
+
only when the host can read project bundles. The field names and defaults are unchanged.
|
|
158
|
+
- **Breaking:** `kiln_edit capture`, `kiln_view_interior capture`, `kiln_inspect shot` and
|
|
159
|
+
`kiln_screenshot_animation shot` are advertised as opaque records; `kiln_render` states the
|
|
160
|
+
capture shape in full, `shape:capture` and `shape:camera-shot` describe it, and each tool
|
|
161
|
+
validates the record as before when it runs. The capture schemas live in
|
|
162
|
+
`src/tools/capture-input.ts`.
|
|
163
|
+
- `kiln_validate`, `kiln_render`, `kiln_edit`, `kiln_inspect`, `kiln_view_interior` and
|
|
164
|
+
`kiln_screenshot_animation` accept `file`, a program file inside the workspace named
|
|
165
|
+
relative to its root, beside `code` and `programRef`; absolute paths and `..` are refused
|
|
166
|
+
with the rule. A code-mode harness can hand Kiln a path instead of quoting a program.
|
|
167
|
+
- The configured project is visible: `kiln_discover` capabilities carry
|
|
168
|
+
`project.configured`, the overview says to read it first, and a project-bound render,
|
|
169
|
+
edit, inspection or save result carries `project: { projectId, revisionId }`.
|
|
170
|
+
- **Breaking:** the server instructions are 692 characters (2,297 before), name no absolute
|
|
171
|
+
path and point at `skills/` beside the server; the list of skills and the offer to copy
|
|
172
|
+
them into `.claude/skills/` or `.agents/skills/` moved out. Workspace selection and
|
|
173
|
+
camera field text is shorter, and every description opens with its purpose.
|
|
174
|
+
- `docs/tools.md` is the packaged manifest pretty-printed (seventeen tools, the advertised
|
|
175
|
+
bytes), no longer the embedding registry's fourteen.
|
|
176
|
+
- `kiln_material` accepts `resourceId`, the name a project's palette and
|
|
177
|
+
`materialDependencies` give a material, as an alias of `materialId` (a Codex session
|
|
178
|
+
passed it twice and was refused both times); the advertised schema and the docs keep
|
|
179
|
+
`materialId`, and a call naming both with different values is refused with the fix.
|
|
180
|
+
- **Breaking** for a call that pins another revision of a project's material: a project
|
|
181
|
+
revision implies its material pins, and a pin the call names replaces the project's or
|
|
182
|
+
the inherited one for the same `resourceId` instead of being refused as a conflict (a
|
|
183
|
+
Codex session repeated the project's five pins on every render, edit, inspect and
|
|
184
|
+
animation call, 1,300 to 3,400 characters of arguments each, because the field said
|
|
185
|
+
project locks could not be replaced). The `materialDependencies` description of the
|
|
186
|
+
six workspace-bound tools says so in the same number of bytes.
|
|
187
|
+
|
|
188
|
+
### Program handles
|
|
189
|
+
|
|
190
|
+
- A `programRef` the store does not know comes back as a tool result that names the next
|
|
191
|
+
call (`kiln_validate` or `kiln_render` with `code`) and no local path. `kiln_validate`,
|
|
192
|
+
`kiln_render`, `kiln_edit`, `kiln_inspect`, `kiln_view_interior` and
|
|
193
|
+
`kiln_screenshot_animation` state the retention of the handle they return: the packaged
|
|
194
|
+
file store keeps it across sessions and processes without eviction. `ProgramStore` gains
|
|
195
|
+
an optional `retention` sentence for injected stores, and `docs/tools.md` states the
|
|
196
|
+
packaged store's.
|
|
197
|
+
|
|
198
|
+
### Results
|
|
199
|
+
|
|
200
|
+
The baseline sessions measured a `detail: 'full'` render of 79,078 characters (cut near
|
|
201
|
+
40,000 before Codex's model saw it; 24% of it line breaks and indentation), 41 copies of
|
|
202
|
+
one finding with the same 300-character repair text, and Agy writing every result over
|
|
203
|
+
about 4,000 characters to a file the model then read back. A default result is now at
|
|
204
|
+
most 20,000 characters and no result is over 40,000; on a 97-part fixture whose every
|
|
205
|
+
part floats, the compact render result is 9,103 characters, `full` 16,734 and `lean`
|
|
206
|
+
2,018. `src/__tests__/result-contract.test.ts` and `mcp-errors.test.ts` hold the rules.
|
|
207
|
+
|
|
208
|
+
- **Breaking:** every tool result is JSON on one line. A render, edit, inspection,
|
|
209
|
+
interior or animation result leads with `ok`, `acceptance`, `disposition`, up to eight
|
|
210
|
+
`blockers` (grouped by code with the repair text once), the `findings` counts and
|
|
211
|
+
`next`, the sentence naming the next call; the `programRef` follows, then the metrics.
|
|
212
|
+
- **Breaking:** the compact report groups the findings of each dimension by code, most
|
|
213
|
+
severe first: one record per code with `count`, the first affected entity and up to two
|
|
214
|
+
`alsoAffected`, `findingsTotal`, and `findingsOmitted`/`omittedByCode` beyond twelve
|
|
215
|
+
groups. The rule records collapse to `ruleSummary` (`evaluated`, `notEvaluated`;
|
|
216
|
+
`notRequested` rules are not listed). `viewEvidence` carries `current` and the hash-only
|
|
217
|
+
`lastFaithful`, not the faithful history. The part
|
|
218
|
+
preview is 24 paths with `partsNextOffset` and the `kiln_inspect listParts` hint.
|
|
219
|
+
Build warnings are at most twelve of 1,000 characters each with `warningsOmitted`.
|
|
220
|
+
- `detail` on `kiln_render`, `kiln_edit`, `kiln_inspect`, `kiln_view_interior` and
|
|
221
|
+
`kiln_screenshot_animation` takes `lean`, `compact` (default) or `full`. `lean` is the
|
|
222
|
+
verdict, blockers, counts, next step, metrics, a short fidelity receipt and three
|
|
223
|
+
warnings. `full` is every finding, rule and part that fits 40,000 characters, with
|
|
224
|
+
`retainedReport: { operationId, path }` naming `.kiln/review/<operation>/evaluation.json`
|
|
225
|
+
(now pretty-printed) when Live Review records the operation; when the complete report
|
|
226
|
+
does not fit, the warnings are bounded first, then repeated findings group by code
|
|
227
|
+
with every rule kept, then the part list shrinks and the groups halve, and
|
|
228
|
+
`qaReport.detail` reads `full-bounded`. The packaged host reads `KILN_RESULT_DETAIL`
|
|
229
|
+
(`lean` or `compact`) as its default.
|
|
230
|
+
- **Breaking:** a `kiln_edit` result is `ok`, `applied`, `changed` (status, part and
|
|
231
|
+
animation summaries, the first five changes), `next`, the `diff` (2,000 characters in
|
|
232
|
+
`lean`, with `diffOmitted`), `preservation` (not in `lean`) and the compacted `render`.
|
|
233
|
+
The compact `preservation.comparison` is the counts, the artifact before and after and
|
|
234
|
+
up to twelve changes as path, name, status and changed fields; the bounds of each
|
|
235
|
+
change and the scope sentences stay in `full` (a live compact edit of a 49-part asset
|
|
236
|
+
measured 20,069 characters with them, 7,191 of it the comparison). When a compact edit
|
|
237
|
+
would still pass 20,000 characters, its `diff` is shortened first, never below 2,000,
|
|
238
|
+
with `diffOmitted`.
|
|
239
|
+
- **Breaking:** a `kiln_inspect compare` page in `compact` or `lean` is the same shape:
|
|
240
|
+
the counts, the artifact before and after, `offset`, `nextOffset` and each change of
|
|
241
|
+
the page as path, name, status and changed fields. A live compact page of 50 changes
|
|
242
|
+
measured 38,952 characters with their bounds and the scope sentences; `detail: 'full'`
|
|
243
|
+
keeps them.
|
|
244
|
+
- **Breaking:** in `compact` and `lean` detail a per-view receipt (`derivativeReceipts`,
|
|
245
|
+
and `viewFidelity.receipts` of shot and animation results) is its `derivativeLabel`,
|
|
246
|
+
`cameraFidelity`, `captureCache` and only the fidelity fields that differ from the
|
|
247
|
+
result's `viewFidelity`; the camera is in `cameraShots` under the same name. A live
|
|
248
|
+
six-shot compact edit measured 22,417 characters with 4,672 of receipts repeating the
|
|
249
|
+
summary and the cameras; `full` keeps whole receipts.
|
|
250
|
+
- **Breaking:** a compact or lean result rounds every number to six decimals (a micrometre
|
|
251
|
+
on a metre-scale asset); `full` and the retained report keep every digit. The 17-digit
|
|
252
|
+
doubles of bounds, cameras and origins were 4,346 of a live 24,223-character compact
|
|
253
|
+
animation result and 1,514 of a 20,556-character compact six-shot edit.
|
|
254
|
+
- **Breaking:** in `compact` and `lean` detail, frames of an animation that resolve to one
|
|
255
|
+
shot are stated once in `cameraShots` with `frames` counting them and each frame's
|
|
256
|
+
bounds in `poseBounds` (nine frames repeated a 631-character camera and subject, 5,666
|
|
257
|
+
characters); `viewFidelity` states once what every receipt shares (the renderer id, a
|
|
258
|
+
degrade reason); and `viewEvidence.lastFaithful` is omitted when it is the current view.
|
|
259
|
+
When nine phases and many measured parts would still pass 20,000 characters, the leading
|
|
260
|
+
frames of `poseBounds` stay whole and `poseBoundsOmitted` counts the rest, with
|
|
261
|
+
`poseBoundsHint` naming the way to them; `full` keeps every frame that fits 40,000.
|
|
262
|
+
- **Breaking:** a `detail: 'full'` edit is bounded as a whole. A live full edit measured
|
|
263
|
+
40,533 characters: its render bounded at 40,000 on its own, the 8,177-character diff and
|
|
264
|
+
the 10,973-character comparison on top. The diff shrinks first (to 2,000, with
|
|
265
|
+
`diffOmitted`), then the bounds of each change leave the comparison (the retained report
|
|
266
|
+
keeps them), then the render is bounded again with what is left.
|
|
267
|
+
- **Breaking:** `kiln_edit` no longer echoes the patched source when the program was sent as
|
|
268
|
+
`code`: a live edit of a 13,173-character program came back at 28,539 characters, the
|
|
269
|
+
source beside the render. The retained `programRef` serves it through `kiln_source`;
|
|
270
|
+
`includeCode: true` asks for it, bounded with the rest of the result (`codeOmitted`,
|
|
271
|
+
`codeHint`).
|
|
272
|
+
- An invalid-input error no longer ends an issue sentence twice (`...or file.. Check`), and
|
|
273
|
+
one that names a key the tool does not take lists the keys it does (`kiln_material takes
|
|
274
|
+
action, materialId, ...`): a live session passed a project palette's `resourceId` to
|
|
275
|
+
`kiln_material get` twice and was told only to check the schema. The `materialId`
|
|
276
|
+
description names the palette's `resourceId`. A nested record the image tools enforce
|
|
277
|
+
when they run (`shot`, `capture`) that fails to parse is the same kind of sentence naming
|
|
278
|
+
the record's Discovery shape, as a tool error: a live session put the camera fields at the
|
|
279
|
+
root of a `shot` and received `ok: false` with zod's issue dump under "Fix the error in
|
|
280
|
+
the source".
|
|
281
|
+
- `kiln_assets get` and `restore` without `revisionId` read the asset's newest revision (the
|
|
282
|
+
one no later revision names as its parent), and `kiln_material get` without `revisionId`
|
|
283
|
+
reads the material's only revision, naming the revisions when there are several; both
|
|
284
|
+
match `kiln_project get`. Three live sessions called `get` with the id alone and were
|
|
285
|
+
refused.
|
|
286
|
+
- **Breaking:** `kiln_inspect listParts` returns names and paths; `placement: true` adds
|
|
287
|
+
the world transform, mirroring and bounds in pages of 50. The floating-parts warning
|
|
288
|
+
names the first six parts with their fix and the next 24 by name, and a render result
|
|
289
|
+
carries the export-time structural warnings once (a second pass over the re-imported
|
|
290
|
+
scene repeated every floating part under its primitive name).
|
|
291
|
+
- **Breaking:** `kiln_review list` pages (`offset`, `limit` up to 100, default 20) and
|
|
292
|
+
returns short records (`operationId`, `revision`, `tool`, `status`, timestamps,
|
|
293
|
+
`programRef`, `pinned`, the artifact hash, capture count and fidelity) with `total` and
|
|
294
|
+
`nextOffset`; `get` and `pin` return an operation bounded to 20,000 characters, naming
|
|
295
|
+
the retained file for what was left out. `kiln_discover` detail pages stop at 15,000
|
|
296
|
+
characters and name the ids not returned in `omittedIds`.
|
|
297
|
+
- **Breaking:** a result with `ok: false` is an MCP error (`isError: true`). Every error
|
|
298
|
+
names the next call and no absolute local path: an invalid input is a sentence naming
|
|
299
|
+
the fields and the `shape:` id to read instead of a zod issue dump; an unknown project,
|
|
300
|
+
material, asset or review id names the `list` action; a renderer that is required but
|
|
301
|
+
unavailable names `KILN_RENDER`, `KILN_RENDER_PORT_URL` and `kiln_renderer reprobe`;
|
|
302
|
+
`kiln_review save` names the revision or status to fix; a project import refusing its
|
|
303
|
+
own id says to pass a different `--id`; a shot whose subject names no node, or more
|
|
304
|
+
than one, is answered with the shot's fix (one exact part path from the list in the
|
|
305
|
+
error), not the source's.
|
|
306
|
+
- The CLI `render --json` and `animation --json` receipts carry the compact result by
|
|
307
|
+
default (one receipt measured 51,312 characters at `full`); `--detail lean|compact|full`
|
|
308
|
+
selects the detail. The CLI `material list` prints the summaries `kiln_material list`
|
|
309
|
+
returns, not every manifest (34,116 characters for five pinned materials before).
|
|
310
|
+
- `scripts/tier2-dogfood.mjs` counts the tool steps of an Agy stream (`step_update` with
|
|
311
|
+
`tool_name`, one per step index), so a blind Agy run's receipt no longer says `unknown`.
|
|
312
|
+
- A saved manifest read as a resource (`kiln://assets/.../manifest.json`) is one line, as
|
|
313
|
+
every tool result is; the file on disk stays pretty-printed. CLI `kiln asset <id>`
|
|
314
|
+
without a revision reads the asset's newest revision, as `kiln_assets get` does (it
|
|
315
|
+
refused with "requires asset ID and revision ID"), while `export` still names one exact
|
|
316
|
+
revision; `kiln save --help` prints the save usage alone (a blind OpenCode run read
|
|
317
|
+
2,275 characters of the assets-and-viewer block for it, and the whole block had been
|
|
318
|
+
16,077 before the records trim).
|
|
319
|
+
|
|
320
|
+
### Generated code
|
|
321
|
+
|
|
322
|
+
The follow-ups the owner decided on 2 October 2026 after reading the cycle's report
|
|
323
|
+
(decisions 23 to 28 in the plan) land here, on the same branch, before it merges.
|
|
324
|
+
|
|
325
|
+
- **Breaking:** generated code runs in strict mode. The evaluator prepends `'use strict'`
|
|
326
|
+
to every program and `kiln_validate` parses with the same directive, so a construct only
|
|
327
|
+
strict mode refuses (`with`, a legacy octal literal, a duplicate parameter name) is a
|
|
328
|
+
`SYNTAX_ERROR` with its line before any evaluation; an assignment to an undeclared name
|
|
329
|
+
throws (answered as an unbound variable) instead of creating a host global; and a
|
|
330
|
+
function declared inside a block stays in that block. The source policy allows `this`
|
|
331
|
+
inside object-literal methods, getters, setters and function properties, class methods,
|
|
332
|
+
constructors, accessors, field initializers and static blocks, and in arrows nested
|
|
333
|
+
inside those, where it is the receiver the program built (w29's mesh batcher was an
|
|
334
|
+
object literal whose `add` method read `this`); `this` at the top level or in a plain
|
|
335
|
+
function stays `UNSAFE_GLOBAL_ACCESS`, as does `module`.
|
|
336
|
+
- The generic rejection carries the engine's own advice. A program that throws without
|
|
337
|
+
a closed cause is still answered `Generated asset execution was rejected.` with no
|
|
338
|
+
message, stack or identifier from it; that sentence now continues with a fixed
|
|
339
|
+
engine-owned paragraph saying so and naming the way to read values (`kiln_inspect` on
|
|
340
|
+
a rendered program, not a thrown `Error`) and the way to find the line
|
|
341
|
+
(`kiln_validate`). The scene session that threw an `Error` to print bounding boxes got
|
|
342
|
+
the bare sentence (H30). A rejection with a cause keeps that cause's advice alone; the
|
|
343
|
+
wire message and the adversarial isolation test's exact first sentence are unchanged.
|
|
344
|
+
|
|
345
|
+
### Knowledge and setup
|
|
346
|
+
|
|
347
|
+
Standing knowledge is read whole at the start of every session and again after each
|
|
348
|
+
compaction, so it is a budget: the generated guide is at most 5,000 characters and a
|
|
349
|
+
`SKILL.md` at most 16,000 characters and 500 lines, enforced by the workspace tests and
|
|
350
|
+
`check:skills`.
|
|
351
|
+
|
|
352
|
+
- **Breaking** for generated workspaces: `AGENTS.md` carries a 4,461-character guide
|
|
353
|
+
(10,716 before) and `CLAUDE.md` is the one-line import `@AGENTS.md`. Claude Code 2.1.287
|
|
354
|
+
loads `AGENTS.md` by default only where no `CLAUDE.md` exists, so the import keeps one
|
|
355
|
+
copy of the guide in context whichever file it reads. A workspace carries one skill
|
|
356
|
+
registry, the directory its harness reads: `.claude/skills/` for Claude Code (whose binary
|
|
357
|
+
also names `.agents/skills`, so the two copies registered every skill twice),
|
|
358
|
+
`.agents/skills/` for codex, hermes, agy, copilot and cursor-agent, and none for OpenCode,
|
|
359
|
+
whose `opencode.json` names `skills/` in `skills.paths`. Existing workspaces are not
|
|
360
|
+
rewritten: `kiln-init --check` reports the second registry a 0.9 workspace carried as
|
|
361
|
+
`retired`, `--upgrade` removes it when unchanged and stops on an edited copy.
|
|
362
|
+
- `kiln-author-asset/SKILL.md` is 15,969 characters (19,030 before). Its delivery paragraph
|
|
363
|
+
offers `node kiln.mjs view` to a person who is present instead of telling the agent to
|
|
364
|
+
launch it: a headless Codex session saved its asset and then sat behind the viewer until
|
|
365
|
+
the 30-minute cap. The author, QA and camera guidance make the compact result the way
|
|
366
|
+
to review and name `detail: "full"` only as a qualified second look: the first wave
|
|
367
|
+
pair asked `full` on every render and edit in both the compact and the lean arm because
|
|
368
|
+
the skills said to pass it "for every finding". `check:skills` now refuses a skill
|
|
369
|
+
sentence that names full detail without "only". `engine-handoff.md` lives once in `kiln-qa-asset` and
|
|
370
|
+
`export-profiles.md` once in `kiln-author-asset`, each named by skill and path from the
|
|
371
|
+
other (a skill's markdown links stay inside the skill, so a workspace that installs one
|
|
372
|
+
skill alone resolves every link); `check:skills` refuses two files under `skills/` with the
|
|
373
|
+
same bytes.
|
|
374
|
+
- Codex: the generated `.codex/config.toml` is read once `$CODEX_HOME/config.toml` marks
|
|
375
|
+
the project trusted (measured on 0.160.0; the generator and `START.md` said Codex read no
|
|
376
|
+
project-local config), `node codex.mjs` applies the same values per run so no trust entry
|
|
377
|
+
is needed, and its `env_vars` forward `KILN_PROJECT`, so a configured project reaches the
|
|
378
|
+
server under Codex as it does elsewhere. `kiln-init --help` lists all seven harnesses.
|
|
379
|
+
- Antigravity: the generated `.agents/mcp_config.json` sets `KILN_RESULT_DETAIL=lean` on
|
|
380
|
+
the server entry. Antigravity writes a result over about 4,000 characters to a file the
|
|
381
|
+
model then reads back, and the wave's paired sessions showed lean winning both measures
|
|
382
|
+
only there (24% fewer result characters, 8% fewer output tokens); the other harnesses'
|
|
383
|
+
entries set nothing and keep the compact default, and a call's own `detail` still wins.
|
|
384
|
+
An existing Antigravity workspace shows the entry as changed managed configuration to
|
|
385
|
+
`kiln-init --check`; `--upgrade` refreshes it when the file is unedited.
|
|
386
|
+
- Records: the plugin manifests say 0.10.0 and `kiln` (the Codex plugin manifest said
|
|
387
|
+
`kiln-oss`), the root `plugin.json` no longer names a schema URL that returns 404,
|
|
388
|
+
`docs/dogfooding.md` and `docs/clean-room.md` name OpenCode's `--standalone` (there is no
|
|
389
|
+
`--pure` in 2.0.14), `docs/harnesses.md` records the measured skill directories and the
|
|
390
|
+
Codex trust rule, and the Tier 2 driver reads the packaged manifest for the tool names it
|
|
391
|
+
counts as workspace MCP use (its hand-kept list lacked `kiln_discover`, `kiln_renderer`,
|
|
392
|
+
`kiln_project`, `kiln_material` and `kiln_review`).
|
|
393
|
+
|
|
394
|
+
## 0.9.0
|
|
395
|
+
|
|
396
|
+
**Source and site preview for dogfooding.** The v0.9 work is integrated for the
|
|
397
|
+
Cloudflare site rollout. Package publication remains deferred to v1.0 after feedback.
|
|
398
|
+
Individual asset review status is recorded on its page; deployment does not change it.
|
|
399
|
+
|
|
400
|
+
Kiln 0.9.0 adds optional projects, a material library and Live Review to standalone
|
|
401
|
+
authoring, makes the calibrated `review-neutral-v1` rig the default for review views,
|
|
402
|
+
exports declared levels of detail as `MSFT_lod` chains, and fixes the defects authors
|
|
403
|
+
reported while using 0.8. Standalone assets need no project. The [migration notes](docs/migration.md#changes-in-090) list every change an
|
|
404
|
+
existing author will notice; the [foundation checkpoint](docs/plans/2026-09-26-project-foundation.md)
|
|
405
|
+
records how projects, materials and Live Review were qualified.
|
|
406
|
+
|
|
407
|
+
### Projects, materials and Live Review
|
|
408
|
+
|
|
409
|
+
- **Optional projects.** `kiln_project` and `node kiln.mjs project` create, read and
|
|
410
|
+
update immutable, versioned project records: brief, inventory, design profile,
|
|
411
|
+
references, delivery intent and an exact material dependency lock. Updates name the
|
|
412
|
+
expected revision and report conflicts. Work stays standalone unless an operation
|
|
413
|
+
selects a project (`--project`, MCP `projectId`) or the host configures
|
|
414
|
+
`KILN_PROJECT`; `--no-project` and `projectId: null` override that default. The
|
|
415
|
+
collection named `project` remains only a save destination.
|
|
416
|
+
- **Material library.** `kiln_material` and `node kiln.mjs material` keep immutable
|
|
417
|
+
material revisions with creator, license, recipe, seed and source provenance. Five
|
|
418
|
+
offline procedural presets (`warm-brick`, `wood-grain`, `brushed-metal`,
|
|
419
|
+
`woven-fabric`, `coarse-soil`) each produce base colour, normal and packed
|
|
420
|
+
metallic/roughness maps. Custom procedural drafts, normal-from-height derivation and
|
|
421
|
+
complete payload import and export are supported. Source compiles a returned
|
|
422
|
+
`portableSpec` with `compilePortableMaterialSpecV2`; the exact pins travel as
|
|
423
|
+
`materialDependencies` or `--materials`.
|
|
424
|
+
- **Live Review.** `node kiln.mjs view` opens the local dashboard: Library, Materials,
|
|
425
|
+
Projects and Live Review. Live Review shows the exact retained artifacts, captures
|
|
426
|
+
and fidelity of CLI and MCP operations, with iterations, errors, pinning, comparison
|
|
427
|
+
and reconnection. `kiln_review` lists, gets and pins observed operations and saves an
|
|
428
|
+
exact reviewed operation. `KILN_WORK_ITEM` optionally groups one authoring item across
|
|
429
|
+
sessions. The Measure control records a bounded browser load and frame sample.
|
|
430
|
+
- **Delivery.** `project export --profile editable|runtime` packages a project's linked
|
|
431
|
+
saved revisions; editable packages rebuild offline from source, settings and
|
|
432
|
+
complete material resources, and `asset ... --rebuild` reports artifact hash equality.
|
|
433
|
+
The Library aggregates configured collections with collection-qualified IDs.
|
|
434
|
+
- **Seventeen MCP tools.** The packaged stdio server lists the fourteen program tools
|
|
435
|
+
plus `kiln_project`, `kiln_material` and `kiln_review`. Embeddings advertise those
|
|
436
|
+
three only when their host services are supplied.
|
|
437
|
+
|
|
438
|
+
### Review lighting and provenance
|
|
439
|
+
|
|
440
|
+
- **`review-neutral-v1` is the default review rig**: a calibrated white rig with
|
|
441
|
+
Review Neutral, a Khronos PBR Neutral variant. A key-facing matte `#C0362C` panel
|
|
442
|
+
reads `(193,51,40)` instead of `(255,177,147)`; mean CIEDE2000 over the ColorChecker
|
|
443
|
+
chart falls from 28.09 to 0.51. `neutral-studio-v1` and `gallery-studio-v1` stay
|
|
444
|
+
selectable by explicit lighting ID, captures without one re-render after the upgrade,
|
|
445
|
+
and composer's unsupported `neutral-studio-v2` default becomes `review-neutral-v1`.
|
|
446
|
+
Do not darken albedo for review lighting.
|
|
447
|
+
- The CLI honours `KILN_RENDER` on every renderer-selecting path: an explicit
|
|
448
|
+
`--render` wins, then `KILN_RENDER`, then auto.
|
|
449
|
+
- Saved builds record the installed engine under every build-cache policy, and an
|
|
450
|
+
absent optional peer is fingerprinted as peer-absent instead of erasing the runtime
|
|
451
|
+
identity.
|
|
452
|
+
|
|
453
|
+
### Levels of detail
|
|
454
|
+
|
|
455
|
+
- **One tier unless the brief asks.** The authoring skills say so. Tiers are sibling
|
|
456
|
+
groups named with one stem and a level token (`Body_LOD0`, `Body_LOD1`), LOD0 the
|
|
457
|
+
full-detail tier, and each set is declared once with
|
|
458
|
+
`defineLod(levels, { screenCoverage })`: one screen fraction per level, 0 to 1,
|
|
459
|
+
strictly decreasing, where a last value of 0 never culls. `createPart` is unchanged.
|
|
460
|
+
Two or more sibling tiers without a declaration, a gap, a missing LOD0 or a set
|
|
461
|
+
declared inside another tier fail the build with the closed diagnostic `LOD_SET`.
|
|
462
|
+
- **Exported as `MSFT_lod`.** Every GLB Kiln writes from source (the saved `asset.glb`,
|
|
463
|
+
`kiln_export`, `kiln export`, `render --out`, both export profiles, both converters)
|
|
464
|
+
carries each set as one chain: LOD0 stays in the scene with `extensions.MSFT_lod.ids`
|
|
465
|
+
and `extras.MSFT_screencoverage`, the lower levels leave the scene with their subtrees
|
|
466
|
+
and transforms, and materials are untouched. A loader without the extension draws
|
|
467
|
+
LOD0.
|
|
468
|
+
- **LOD0 is the headline.** Triangles and bounds count LOD0 and the parts outside every
|
|
469
|
+
set; `levelsOfDetail` in render results, the integration manifest and CLI receipts
|
|
470
|
+
lists each level's path and triangles.
|
|
471
|
+
- **Review views.** Default sheets in `kiln_render`, `kiln_inspect` and the `kiln_save`
|
|
472
|
+
preview draw LOD0. A shot whose subject is a lower level's `path` draws that level in
|
|
473
|
+
LOD0's place (`visibility: "isolate"` shows it alone), the CPU and GPU views agree,
|
|
474
|
+
and each chain's `drawn` says which level every view drew. No tool input changed.
|
|
475
|
+
- **Viewer.** Library and Live Review show a Level control (LOD0 to the last level,
|
|
476
|
+
LOD0 by default) and every level's triangles for a GLB with chains, imported or
|
|
477
|
+
authored. Expand **Per-part levels** to choose each independent chain, such as a
|
|
478
|
+
medium tractor body with detailed wheels. Mixed selections report the triangles
|
|
479
|
+
actually displayed. Current and pinned Live Review artifacts have their own part
|
|
480
|
+
controls; the current artifact's global selector still sets both views. Selecting
|
|
481
|
+
another observation of identical bytes retains geometry statistics and updates
|
|
482
|
+
the observation identity.
|
|
483
|
+
- **Revision comparison** reads chains: each lower level is compared at the path it
|
|
484
|
+
takes beside LOD0. Switch thresholds are not compared.
|
|
485
|
+
|
|
486
|
+
### Authoring and review contracts
|
|
487
|
+
|
|
488
|
+
- Part listings include world position, quaternion, scale, mirrored orientation and
|
|
489
|
+
world bounds, including compact results.
|
|
490
|
+
- Node and material `userData` round-trips through glTF extras: plain JSON, at most
|
|
491
|
+
4 KiB per object and 64 KiB per asset. `kiln*` keys remain engine-owned. Validation
|
|
492
|
+
reports literal problems; builds report omitted dynamic values. Optimization keeps
|
|
493
|
+
metadata-bearing nodes and materials instead of merging away their identities.
|
|
494
|
+
- `visible = false` survives export as `KHR_node_visibility`. Headline metrics and
|
|
495
|
+
category QA exclude hidden subtrees; `hiddenNodes` reports their triangle counts.
|
|
496
|
+
Instancing and flattening preserve the flag and its ancestor scope.
|
|
497
|
+
- `markOpenShell(part, reason)` acknowledges an intentionally unmeasurable open shell
|
|
498
|
+
without suppressing measured overlap or other failures. Overlapping closed components
|
|
499
|
+
use union volume; unsupported inward shells and component budgets remain unmeasured.
|
|
500
|
+
- `CUBICSPLINE`, `EASE_IN`, `EASE_OUT` and `EASE_IN_OUT` tracks export standard cubic
|
|
501
|
+
samplers with computed tangents and play consistently in review. Quaternion loop
|
|
502
|
+
closure treats `q` and `-q` as the same rotation.
|
|
503
|
+
- Source exports index unindexed primitives by welding exact complete vertices.
|
|
504
|
+
`indexPolicy: 'asBuilt'` (local host: `KILN_INDEX_POLICY=asBuilt`) retains helper
|
|
505
|
+
buffers and requires optimization off. Render results and CLI receipts report the
|
|
506
|
+
index pass's accessor payload bytes before/after, separately from GLB file size.
|
|
507
|
+
- Sweep and loft helpers observe tight curvature and intersecting consecutive rings
|
|
508
|
+
with station evidence. The bounded local check replaces unconditional unchecked
|
|
509
|
+
warnings; budget-limited checks remain explicitly partial. Distant segments are
|
|
510
|
+
outside this check.
|
|
511
|
+
- `kiln.capture.v2` adds shot-level `hide` with exact paths or unique names. Version 1
|
|
512
|
+
and legacy captures remain valid. CPU and GPU derivatives apply the same hide list;
|
|
513
|
+
post-loop CPU captures resolve subjects from the exported hierarchy.
|
|
514
|
+
- Instanced capture derivatives and canonical bounds retain every instance transform.
|
|
515
|
+
Overlap QA excludes alternate levels only within the same LOD chain, and category
|
|
516
|
+
diagnostic sheets show the default LOD0 scene. Render-service startup tolerates a
|
|
517
|
+
concurrent winner's bounded warmup; completed captures verify the service instance.
|
|
518
|
+
|
|
519
|
+
### Fixes from author reports
|
|
520
|
+
|
|
521
|
+
- **Smaller results.** MCP `kiln_render` and `kiln_screenshot_animation` are compact by
|
|
522
|
+
default; `detail: "full"` returns every finding and rule. On the carousel example a
|
|
523
|
+
render result falls from 34,904 to 7,706 characters. `kiln_view_interior`,
|
|
524
|
+
`kiln_inspect` and `kiln_edit` are compact too; the CLI, retained artifacts and Live
|
|
525
|
+
Review keep complete reports.
|
|
526
|
+
- **Sizes and files.** Animation composites take a frame `size` of 128 to 1024 px
|
|
527
|
+
(default 256). Versioned capture shots go up to 2048 px. `--capture` with
|
|
528
|
+
`output: "separate"` writes `<stem>.shot-01.png` and onward.
|
|
529
|
+
- **Animation.** `createClip(name, duration, tracks, { loop })` records loop intent,
|
|
530
|
+
exported as the animation extra `kilnLoopIntent` and checked by review
|
|
531
|
+
(`LOOP_NOT_CLOSED`). GLBs no longer duplicate every clip as the `kilnReviewClipsV1`
|
|
532
|
+
scene extra.
|
|
533
|
+
- **Views.** Saved previews drawn from the persisted GLB record `exactArtifact: true`.
|
|
534
|
+
Isolated capture shots send the GPU only the subject. CPU views draw translucent
|
|
535
|
+
surfaces after opaque ones, farthest first, so glass shows what is behind it. An
|
|
536
|
+
explicit perspective camera without `near` sets it from the nearest geometry.
|
|
537
|
+
- **Geometry and export.** `extrudeProfile` adds no side rings unless `divisions` asks
|
|
538
|
+
(16 by default when twisted). `sweepProfile` keeps hard corners (`creaseAngle` 60)
|
|
539
|
+
and can cap one end. Emissive intensity survives export, above 1 through
|
|
540
|
+
`KHR_materials_emissive_strength`. An imported GLB's `MSFT_lod` chains survive
|
|
541
|
+
import, save, optimisation and export.
|
|
542
|
+
- **Diagnostics.** A build that throws names a closed cause with advice and a
|
|
543
|
+
`Source check:`; `kiln_validate` reports `TEMPORAL_DEAD_ZONE`,
|
|
544
|
+
`MATERIAL_RECIPE_OVERRIDE` and `MATERIAL_RECIPE_ID`. Overlap QA skips LOD
|
|
545
|
+
alternates, tests the likeliest pairs first and groups unmeasurable parts;
|
|
546
|
+
connectivity leaves out LOD1+ parts. Repeated helper notes appear once with a mesh
|
|
547
|
+
count. The instanceability grade says it is informational, the blend-area budget
|
|
548
|
+
names its largest materials, and `kiln_inspect` evaluates without optimisation.
|
|
549
|
+
- **Errors that name candidates.** Ambiguous and missing subjects, unknown camera keys
|
|
550
|
+
(`fovDeg` for `fov`) and missing or shared `surfacePairs` names list what would have
|
|
551
|
+
matched. `surfacePairs` take exact paths or unambiguous node names, as `measure` does.
|
|
552
|
+
Animation `measureParts` entries carry each node's world origin.
|
|
553
|
+
- **Setup and CLI.** A workspace's `kiln.mjs` re-executes under the Node recorded at
|
|
554
|
+
setup, so CLI exports equal `kiln_save` bytes. `.kiln/workspace.json` names the
|
|
555
|
+
bundle `buildIdentity`, apart from the installed `runtimeIdentity`. The viewer
|
|
556
|
+
accepts `localhost` and `[::1]`; Git Bash collection roots are refused on Windows.
|
|
557
|
+
`kiln edit` and `kiln source` accept `--json`, `kiln service start` joins or starts
|
|
558
|
+
the shared renderer, and a render URL naming the shared local socket takes the local
|
|
559
|
+
route.
|
|
560
|
+
|
|
561
|
+
### Fixes from the 0.9 dogfood runs
|
|
562
|
+
|
|
563
|
+
Three blind setup-and-author runs on the packaged build, two in OpenCode and one in Agy,
|
|
564
|
+
found these before release.
|
|
565
|
+
|
|
566
|
+
- **`kiln_edit` results** lead with `programRef` and `parentRef` and carry a compact
|
|
567
|
+
render; `kiln_render({ programRef, detail: "full" })` returns the complete report.
|
|
568
|
+
- **Discovery.** `ids` take a recipe's bare slug (`material-wood-v1`) as well as
|
|
569
|
+
`recipe:material-wood-v1`, and a material recipe's summary names its
|
|
570
|
+
`materialRecipe("kiln.material.wood.v1")` call. Reviewed aliases let `bench`, `table`
|
|
571
|
+
and `cast iron` find the joined-frame recipe, `arrayLinear` and the painted-metal
|
|
572
|
+
material.
|
|
573
|
+
- **One `--json` rule.** `render`, `source`, `export`, `discover`, `inspect`, `animation`
|
|
574
|
+
and `service status`/`reprobe` print a receipt; commands that print JSON already accept
|
|
575
|
+
the flag; `generate`, `view`, `collections add` and `service start`/`stop` refuse it
|
|
576
|
+
and name the commands that take it. `export --json` names each file with its `bytes`
|
|
577
|
+
and `sha256`.
|
|
578
|
+
- **Exports never replace a file.** `export` and `source --out` fail and name the existing
|
|
579
|
+
file; `render --out` still replaces its own working output.
|
|
580
|
+
- **Setup.** `kiln discover --capabilities` reports the collections and source storage the
|
|
581
|
+
MCP server has, and `kiln-init` creates the `.kiln/programs` store it configures.
|
|
582
|
+
- **Guidance.** The OpenCode configuration check, npm 11's `install-scripts` warning for
|
|
583
|
+
`webgpu`, the part rotation convention and which way an object faces, searching with
|
|
584
|
+
`kiln_discover` rather than a harness's own search, observe findings on intended joins,
|
|
585
|
+
suffixed names for repeated sub-assemblies, a user-level `kiln` server beside
|
|
586
|
+
`kiln_workspace`, and where agy's `--print` prompt goes.
|
|
587
|
+
|
|
588
|
+
### Output that changes on upgrade
|
|
589
|
+
|
|
590
|
+
Review colours under the new rig (assets darkened for the old rig look too dark);
|
|
591
|
+
untwisted `extrudeProfile` triangle counts; `sweepProfile` shading of triangular, square and
|
|
592
|
+
pentagonal profiles (pass `creaseAngle: 180` for the old smooth look); GLB bytes
|
|
593
|
+
of emissive and animated assets; images from explicit perspective cameras without
|
|
594
|
+
`near`; CPU images through glass; GPU isolated shots; MCP result size and shape
|
|
595
|
+
(`detail: "full"` restores the complete report), including `kiln_edit`, which leads with
|
|
596
|
+
its refs; the wording of refused exports; Discovery ranking for `bench`, `table` and
|
|
597
|
+
`cast iron`. A program with two or more sibling `LOD<n>` tiers fails with `LOD_SET`
|
|
598
|
+
until it declares them with `defineLod` or keeps one tier; once declared, its GLB bytes,
|
|
599
|
+
headline triangles and bounds, and default sheets (LOD0 only) change.
|
|
600
|
+
|
|
601
|
+
## 0.8.0 (source update)
|
|
602
|
+
|
|
603
|
+
The 0.8.0 source update exposes Original GLB and Runtime GLB downloads in the local
|
|
604
|
+
viewer and public gallery, with companion runtime metadata and unchanged canonical
|
|
605
|
+
files. The public viewer adds native animation selection and pause/play controls.
|
|
606
|
+
Gallery build scripts use the current evaluator API. Site setup text and
|
|
607
|
+
historical-example labels match the upgraded CLI/MCP workflow.
|
|
608
|
+
|
|
609
|
+
External CLI/MCP authoring skills and native Strands workflow instructions are
|
|
610
|
+
separate. Optional native references expose only explicitly selected technical
|
|
611
|
+
files, with no workspace setup, CLI command or delivery instructions.
|
|
612
|
+
|
|
613
|
+
- **One asset workflow across CLI and MCP.** Kiln Discovery replaces
|
|
614
|
+
`kiln_list_primitives`; search ordinary modeling language, browse operations,
|
|
615
|
+
assemblies and optional recipes, then fetch exact contracts. No search model,
|
|
616
|
+
GPU, API key or category selection is required. Matching now normalizes Unicode
|
|
617
|
+
identifiers, retains term/field evidence, labels related and partial results,
|
|
618
|
+
and limits typo expansion to missing vocabulary.
|
|
619
|
+
- **Explicit migration instead of hidden legacy fallbacks.** Retired Discovery
|
|
620
|
+
selectors, ambiguous helper aliases, category-driven execution and the old
|
|
621
|
+
evaluator/native interfaces fail with migration advice. See
|
|
622
|
+
[the migration guide](docs/migration.md) before updating an integration.
|
|
623
|
+
- **Geometry and assembly contracts are sharper.** The unification pass repairs
|
|
624
|
+
scale-sensitive geometry diagnostics, sweeps, CSG precision/attributes, UV
|
|
625
|
+
ownership and assembly reuse. Requirements and QA report unsupported obligations
|
|
626
|
+
as incomplete; successful generation does not certify an asset's physical fit.
|
|
627
|
+
- **Better evidence during review.** Animation review reports endpoint continuity
|
|
628
|
+
separately from loop intent and velocity smoothness. Rendered edits automatically
|
|
629
|
+
compare exported static data and animation channels; source-only edits explicitly
|
|
630
|
+
leave preservation unassessed. Focused inspection provides paged differences,
|
|
631
|
+
subtree summaries and surface measurements.
|
|
632
|
+
- **A shared renderer with explicit fidelity.** Compatible clients share a managed
|
|
633
|
+
service with an idle lifetime; the starting session's exit does not kill other
|
|
634
|
+
clients' work. Incompatible listeners are reported without replacement. The
|
|
635
|
+
optional renderer ships inside Kiln; local startup, remote routes, cancellation,
|
|
636
|
+
admission limits and in-session reprobe share the documented contracts. Material
|
|
637
|
+
fidelity is reported for each view and CPU views remain geometry-only evidence.
|
|
638
|
+
- **Strands is optional.** Its native workflow uses the shared program-reference
|
|
639
|
+
tools, unified rendering and an explicit `kiln_finish` terminal. Native context
|
|
640
|
+
stays outside the shared CLI/MCP skills; SDK/provider dependencies are optional.
|
|
641
|
+
- **Consumer requirements are separate from maintainer pins.** CLI/MCP accept Node
|
|
642
|
+
20.15.0+ on the 20.x line or 22.2.0+; native Strands requires 22.2.0+. Installed
|
|
643
|
+
commands do not require Bun. Read-only workspace checks respect an existing
|
|
644
|
+
installed interpreter; setup canonicalizes parent directory aliases so macOS temporary
|
|
645
|
+
workspaces remain current after Node resolves their paths. Repair/upgrade remains explicit. OpenCode setup guidance
|
|
646
|
+
reflects its current CLI, and Cline's affected image path has a documented workaround.
|
|
647
|
+
|
|
648
|
+
This source update does not publish a new installable package. Qualification and
|
|
649
|
+
remaining limits are recorded in the [progress checkpoint](docs/plans/2026-09-22-progress-checkpoint.md).
|
|
650
|
+
The development entries below retain earlier changes and may describe intermediate
|
|
651
|
+
interfaces superseded by this version; use the current tool and migration guides.
|
|
652
|
+
|
|
653
|
+
### Test suite holds under a loaded runner
|
|
654
|
+
|
|
655
|
+
- The test scripts and CI set a 20 s per-test budget instead of Bun's 5 s default. Tests that take
|
|
656
|
+
under a second locally (a cold CLI spawn, the first `sharp` decode in a file) had timed out at 5 s
|
|
657
|
+
on the Windows runner and passed on re-run; a real hang still fails, twenty seconds later.
|
|
658
|
+
- The tier-2 driver's process-group test no longer races node start-up. It stopped the run 50 ms
|
|
659
|
+
after spawn, so on a loaded runner the child died before it had spawned its descendant and the
|
|
660
|
+
orphan spawned afterwards survived. The test now waits for the child to announce its descendant
|
|
661
|
+
before interrupting the group, and a separate test proves the deadline reports itself. Temp
|
|
662
|
+
directories that a just-killed process tree still holds are removed with retries instead of
|
|
663
|
+
failing the run with `EBUSY`.
|
|
664
|
+
|
|
665
|
+
### Neutral view backdrop, and a named backdrop per capture
|
|
666
|
+
|
|
667
|
+
- **Every contact sheet is now painted on the neutral studio grey `#aab1bc` instead of near-black
|
|
668
|
+
`#1a1a1a`.** The old value was pinned in PR #13 for CPU/GPU parity and never revisited; a dark
|
|
669
|
+
asset on it lost the silhouette, tail and ground contact the render tool asks the model to check.
|
|
670
|
+
The new default was chosen by measuring silhouette-edge contrast over the 86 examples plus a
|
|
671
|
+
near-black test asset on the CPU rasterizer: near-black left 39.7% of edge pixels under a 1.5:1
|
|
672
|
+
contrast ratio, the studio grey 12.8%. It is also the GPU studio preset's background, so a CPU
|
|
673
|
+
fallback sheet and a GPU sheet of the same request now share one colour on every path,
|
|
674
|
+
including exact-camera captures, which used to come back grey from the GPU and near-black from
|
|
675
|
+
the CPU fallback.
|
|
676
|
+
- **`capture.backdrop` accepts `neutral`, `dark` or `light`** on `kiln_render`, `kiln_edit` and
|
|
677
|
+
`kiln_view_interior`. Free colours are deliberately not accepted: comparability across runs
|
|
678
|
+
assumes two sheets of one GLB differ only because the asset does. The chosen id is part of both
|
|
679
|
+
capture-cache keys and is echoed as `capture.backdrop` in every render result. The render
|
|
680
|
+
service accepts the same `backdrop` field in both modes from a mirrored table that the engine
|
|
681
|
+
suite asserts against. The CLI takes it inside a `--capture` recipe or as `--backdrop <id>`,
|
|
682
|
+
which merges into the same capture object and overrides the recipe's own value, so one shared
|
|
683
|
+
recipe can be re-run on another backdrop without editing it.
|
|
684
|
+
- **The GPU backdrop is pixel-exact.** The service clears the scene background into its HDR
|
|
685
|
+
framebuffer and tone-maps it with the asset, so the neutral `#aab1bc` used to read back as
|
|
686
|
+
`(203, 207, 213)` while the CPU rasterizer painted `(170, 177, 188)`. The service now sets the
|
|
687
|
+
backdrop as the linear colour that comes out of the output pass as exactly the table's bytes,
|
|
688
|
+
through an analytic inverse of three's ACES filmic curve and sRGB transfer in
|
|
689
|
+
`render-service/src/display-transform.mjs`, verified against pixels read back from a dawn-d3d12
|
|
690
|
+
device. A GPU sheet and a CPU sheet of the same request now agree on the backdrop pixel for
|
|
691
|
+
pixel. Compositing after the pass was rejected because multisampled edges would have kept a
|
|
692
|
+
one-pixel fringe.
|
|
693
|
+
- **The render service's free-hex `background` field is gone**, in both modes, along with the
|
|
694
|
+
presets' own background colour: the named backdrop table is the only source, so nothing can
|
|
695
|
+
paint a colour the engine would not. `background` in a request is a 400 naming `backdrop`.
|
|
696
|
+
- **`kiln render --render gpu` no longer hangs after starting the renderer itself.** The host
|
|
697
|
+
kills a service it started from an `exit` hook, which suits the long-lived MCP server, but a
|
|
698
|
+
one-shot command never reached `exit`: the child's piped stderr kept the loop alive, so the
|
|
699
|
+
CLI finished its render and then sat forever with a GPU process orphaned behind it. The CLI
|
|
700
|
+
now stops a service it started when the command settles and leaves one it merely found alone.
|
|
701
|
+
For a batch of CLI renders, start the service once by hand so each command joins it.
|
|
702
|
+
- Occupancy `coverage` takes the backdrop it should measure against. Sheets cached from earlier
|
|
703
|
+
versions are keyed by the old request shape and are simply re-rendered once.
|
|
704
|
+
- `kiln_view_interior` echoes `capture` too, so every image result now says which backdrop its
|
|
705
|
+
silhouettes sat on. The guidance in the schema and skills states one rule for every asset
|
|
706
|
+
colour: switch only after a sheet shows a part merging with the grey, to `light` when that part
|
|
707
|
+
is darker than the grey and to `dark` when it is lighter.
|
|
708
|
+
- **`kiln_save` takes the same `backdrop` for the preview it stores**, as does the CLI's
|
|
709
|
+
`kiln save --backdrop <id>`, and the manifest records the one used as `preview.backdrop`. A
|
|
710
|
+
preview used to be painted on the default whatever sheet had been accepted, so a grey asset
|
|
711
|
+
reviewed on `dark` was stored merging with the grey it had just been moved off.
|
|
712
|
+
|
|
713
|
+
### Experimental community exporter and engine handoff
|
|
714
|
+
|
|
715
|
+
- The established GLB exporter remains the default. Builds containing this integration also
|
|
716
|
+
provide an experimental Three.js exporter for explicit comparison; no separate repository
|
|
717
|
+
is needed. See the [Blender/Unity handoff guide](docs/engine-handoff.md) for scoped CLI/MCP
|
|
718
|
+
activation, restoration of the default, tested import routes and known limitations.
|
|
719
|
+
- Authoring and QA skills include the handoff guide so agents can discover the option when
|
|
720
|
+
destination requirements call for it. Blender/Unity does not automatically select it.
|
|
721
|
+
- Expanded export, GPU, deformation and clean-package checks are documented in the
|
|
722
|
+
[qualification report](docs/evaluation/community-exporter.md). The candidate is not yet
|
|
723
|
+
qualified to replace the default for all supported workflows.
|
|
724
|
+
|
|
725
|
+
### Saved-asset export profiles
|
|
726
|
+
|
|
727
|
+
- Keep byte-preserving `editable` exports as the default. Opt-in `runtime` exports
|
|
728
|
+
move Kiln's duplicated scene review clips to a versioned, hash-linked sidecar,
|
|
729
|
+
preserving standalone native glTF playback and the canonical saved revision.
|
|
730
|
+
Available through the CLI, MCP and `@kiln/engine/asset-export` library entry.
|
|
731
|
+
[Usage, provenance contract and limits](docs/export-profiles.md).
|
|
732
|
+
|
|
733
|
+
## 0.7.1: Preserve CLI outputs on failed writes
|
|
734
|
+
|
|
735
|
+
- GLB, preview PNG, and generated source replacements are written to unique sibling
|
|
736
|
+
temporary files and renamed only after the write closes successfully. A failed
|
|
737
|
+
write or rename leaves the previous output intact. Source and asset exports
|
|
738
|
+
continue to refuse overwrites. Concurrent replacements can fail with a sharing
|
|
739
|
+
violation on Windows; the CLI reports the error without deleting the destination.
|
|
740
|
+
|
|
741
|
+
## The setup defects, and a bind that was never ours to choose — 2026-09-13
|
|
742
|
+
|
|
743
|
+
- **The render service binds loopback now, and widening it costs a token.** `HOST` unset used to
|
|
744
|
+
bind every interface, and the documented manual start -- `npm start`, "nothing else to
|
|
745
|
+
configure" -- did exactly that with `RENDER_SERVICE_TOKEN` unset and only a warning. What sat
|
|
746
|
+
behind it is a `POST /render` that accepts a 48 MB GLB, parses it with three.js and hands the
|
|
747
|
+
buffers to Dawn and a native Vulkan driver, on a queue that renders one frame at a time -- so a
|
|
748
|
+
single caller can hold the GPU indefinitely, and an untrusted binary-asset parser sits in front
|
|
749
|
+
of a kernel driver. That is the shape of CVE-2026-7482, where a crafted model file drove a heap
|
|
750
|
+
overread in a local inference server that operators had put on the public internet by the
|
|
751
|
+
hundred thousand. Their default was loopback; ours was not.
|
|
752
|
+
|
|
753
|
+
The fix is a rule rather than a flag: **the bind address decides whether auth is required.**
|
|
754
|
+
Loopback is free, because the operating system is the boundary. Anything wider requires a token
|
|
755
|
+
and otherwise refuses to boot -- the same choice this file already makes for a software adapter,
|
|
756
|
+
where a driver regression yields a service that will not start rather than one that silently
|
|
757
|
+
does the wrong thing. `RENDER_SERVICE_ALLOW_UNAUTHENTICATED=1` is the explicit waiver, spelled
|
|
758
|
+
so an operator has to type the word. The container image sets `HOST=0.0.0.0` itself, because a
|
|
759
|
+
container binding loopback is unreachable through `-p`. Verified on hardware: a LAN address is
|
|
760
|
+
refused by default, an exposed bind with no token exits 1 before the GPU is even acquired, and
|
|
761
|
+
an exposed bind with one serves while returning 401 without the header.
|
|
762
|
+
|
|
763
|
+
- **Two generated workspaces could not work, and both for the same reason.** A codex workspace
|
|
764
|
+
wrote `.codex/config.toml` that codex never reads -- every source it consults is
|
|
765
|
+
`$CODEX_HOME`-rooted -- so a harness the README lists reached no Kiln tools at all. A hermes
|
|
766
|
+
workspace redirected `HERMES_HOME` to get its MCP servers and skills read, and that one
|
|
767
|
+
variable resolves the config path *and* the credential path, so the run died before its first
|
|
768
|
+
model call. Both now configure **per invocation** through generated launchers: codex via `-c`
|
|
769
|
+
overrides, hermes via `--in` plus the program store riding the environment into the MCP child.
|
|
770
|
+
Neither writes outside the workspace and neither touches authentication. The rule they
|
|
771
|
+
establish: *a workspace may add configuration to an invocation, but it must not replace the home
|
|
772
|
+
that holds credentials.*
|
|
773
|
+
|
|
774
|
+
The hermes diagnosis was wrong before it was right. There is no provider key to inherit --
|
|
775
|
+
`~/.hermes/.env` holds tool toggles and every API key reads "not set", because the provider is a
|
|
776
|
+
subscription OAuth. What the redirect actually lost was `model.default` and `model.provider`.
|
|
777
|
+
Two more things fell out of measuring rather than assuming: `--skills` takes skill *names*, not
|
|
778
|
+
a path, and the documented `--ignore-rules` was suppressing the workspace's own AGENTS.md.
|
|
779
|
+
|
|
780
|
+
- **A launcher test, because that is why nobody saw either one.** `harness-smoke.mjs` invokes each
|
|
781
|
+
CLI directly and never touches the generated launcher, so both defects passed every check. The
|
|
782
|
+
new test asserts the launcher's shape -- that it registers per invocation, parses under the
|
|
783
|
+
interpreter that will run it, and never names the home that holds credentials.
|
|
784
|
+
|
|
785
|
+
- **`arrayLinear` was making copies that were not copies.** It read only `source.position`, so
|
|
786
|
+
every instance stood up straight however the source was laid down -- while `arrayRadial` next
|
|
787
|
+
door set a rotation on every copy. Two dispatched models hit this independently. Copies now
|
|
788
|
+
carry the source's rotation and scale. Separately, `arrayRadial` could only ever orbit the
|
|
789
|
+
parent's origin, which is what its docstring says and not something a caller could work around;
|
|
790
|
+
it takes an optional `center` now. These helpers had no unit tests at all, which is how a
|
|
791
|
+
disagreement between two neighbours survived. **This changes exported geometry** for a program
|
|
792
|
+
that arrays a rotated or scaled source.
|
|
793
|
+
|
|
794
|
+
- **The helper overview stopped making models guess.** A bare `kiln_list_primitives` returned
|
|
795
|
+
names grouped by category and nothing else, and models reliably guessed the JS-conventional
|
|
796
|
+
`createPart(parent, {...})`. The overview now carries the exact signatures of the two helpers
|
|
797
|
+
every program calls, read from the catalog so it cannot drift from what a detail request
|
|
798
|
+
returns.
|
|
799
|
+
|
|
800
|
+
- **`--render gpu` starts the renderer it needs.** It used to throw when nothing was listening
|
|
801
|
+
even though the installation ships a service that could start, because only the MCP server ever
|
|
802
|
+
asked for that. `gpu` means "I asked for a guarantee and would rather know than be quietly
|
|
803
|
+
downgraded"; answering it with a technicality was the defect. `auto` deliberately still does not
|
|
804
|
+
spawn -- a one-shot sheet should not pay a GPU boot. Fixing it also removed a dead `throw` and a
|
|
805
|
+
real crash: the spawn branch read `options.serviceDir` on a path that can now be reached with no
|
|
806
|
+
options at all.
|
|
807
|
+
|
|
808
|
+
- **Which Kiln answered is now a question a tool can settle.** A server named `kiln` may be a
|
|
809
|
+
different installation, and two live examples on one development machine proved it -- an
|
|
810
|
+
extracted 0.6.0 package registered in `~/.cursor/mcp.json` beside a 0.7.0 checkout, and a stale
|
|
811
|
+
cached tool namespace. Both were local leftovers rather than repo defects, but the workspace
|
|
812
|
+
guide has always said "do not substitute it silently" with nothing behind it.
|
|
813
|
+
`kiln_list_primitives {capabilities:true}` now reports `engine.version` and
|
|
814
|
+
`engine.installUrl`, and the guide says to compare them against the workspace manifest.
|
|
815
|
+
|
|
816
|
+
- `zod` 4.6.4 and `webgpu` 0.6.1. The latter was gated on a GPU smoke that has now passed twice:
|
|
817
|
+
`dawn-vulkan` on a GTX 1660 Ti boots and renders through the engine on 0.6.1.
|
|
818
|
+
|
|
819
|
+
## Seven harnesses, one version, and the defects only a plain prompt could find — 2026-09-13
|
|
820
|
+
|
|
821
|
+
- **Two new harness adapters: `copilot` and `cursor-agent`**, bringing the dispatch table to
|
|
822
|
+
seven. Both were verified end to end rather than written from documentation, and both needed
|
|
823
|
+
a flag that is not obvious: Copilot's `--allow-all-tools` is *required* for non-interactive
|
|
824
|
+
mode by its own help, and Cursor needs three separate grants -- `--force` for tool calls,
|
|
825
|
+
`--approve-mcps` for the server, `--trust` for the workspace -- because an unapproved MCP
|
|
826
|
+
server is gated independently of tool permission.
|
|
827
|
+
- **`create-workspace.mjs` learned both harnesses.** Copilot reads a workspace `.mcp.json`,
|
|
828
|
+
the same filename Claude Code reads, and not the same contents: its own `copilot mcp add`
|
|
829
|
+
writes `type: "local"` plus a tool filter where Claude writes `type: "stdio"` and none. The
|
|
830
|
+
generated config is the spelling Copilot produced for itself. Cursor gets `.cursor/mcp.json`.
|
|
831
|
+
- **Tool names are not portable, and a prompt that names one is a harness dependency.**
|
|
832
|
+
Copilot namespaces every MCP tool as `<server>-<tool>`, so an agent asked for
|
|
833
|
+
`kiln_list_primitives` found nothing by that literal name and correctly reported the tools
|
|
834
|
+
missing -- while `copilot -p` listing its own tools showed all thirteen as
|
|
835
|
+
`kiln_workspace-kiln_*`. `harness-smoke.mjs` now says the prefix may exist.
|
|
836
|
+
- **The smoke brief was measuring the wrong thing.** It told the agent to call
|
|
837
|
+
`kiln_list_primitives` and then "nothing else". A bare call returns a compact overview where
|
|
838
|
+
`createPart` is one name among eighteen, and the overview's own first line says to ask again
|
|
839
|
+
with `{names:[...]}` for signatures. Two of five harnesses guessed the JS-conventional
|
|
840
|
+
`createPart(parent, {name, geo, material})` and were rejected at build time; three wrote the
|
|
841
|
+
real positional form. Asking for the signatures made both failures pass with the same models.
|
|
842
|
+
The engine's opaque rejection is not at fault: nothing from a sandboxed exception may cross
|
|
843
|
+
that boundary, by design.
|
|
844
|
+
- **One version, everywhere a client can read it.** `package.json` moved to 0.7.0 and four
|
|
845
|
+
other declarations did not: `plugin.json`, `.claude-plugin/plugin.json`,
|
|
846
|
+
`.codex-plugin/plugin.json` and `MCP_SERVER_VERSION`. Every MCP client reported
|
|
847
|
+
`kiln v0.6.0` against a 0.7.0 engine, which is worth nothing to a bug reporter citing a
|
|
848
|
+
version. A test now asserts all five agree, so the next bump cannot miss them.
|
|
849
|
+
- **Gemini CLI is excluded, not missing.** Google switched it off for individual tiers on
|
|
850
|
+
18 June 2026 in favour of Antigravity CLI; it now fails at startup with
|
|
851
|
+
`IneligibleTierError`. `agy` is the replacement and already had an adapter.
|
|
852
|
+
- **`agy` print mode does not run unattended by itself.** Its log says what happens instead:
|
|
853
|
+
`Print mode: soft-denying tool confirmation "CallMcpTool" at step 10`, then exit 0 with no
|
|
854
|
+
program. It needs `--dangerously-skip-permissions`.
|
|
855
|
+
- **Claude Code's allow-list needed the third server spelling.** `mcp__kiln_workspace` is what
|
|
856
|
+
a generated workspace and a user-level registration both use; with only `mcp__kiln` and
|
|
857
|
+
`mcp__plugin_kiln_kiln` listed, a run stopped and asked for `kiln_list_primitives` by name.
|
|
858
|
+
- New: [docs/harnesses.md](docs/harnesses.md), the per-harness install, upgrade, headless-flag
|
|
859
|
+
and MCP-config reference. [docs/dogfooding.md](docs/dogfooding.md) now opens with the method
|
|
860
|
+
-- three tiers, and why a scripted brief is a wiring probe rather than a dogfood.
|
|
861
|
+
- [ROADMAP.md](ROADMAP.md) carries a stabilisation queue for the first time. The two items at
|
|
862
|
+
the top are setup defects rather than engine defects, and both sit on a path the README
|
|
863
|
+
documents: a generated codex workspace cannot see Kiln at all (codex has no project-local
|
|
864
|
+
config mechanism -- every source is `$CODEX_HOME`-rooted), and a generated hermes workspace
|
|
865
|
+
cannot reach a model (its launcher redirects `HERMES_HOME`, and the provider lives in the
|
|
866
|
+
real home). The codex fix is verified but not applied. The rule it establishes: a workspace
|
|
867
|
+
may add configuration to an invocation, and must not replace the home holding credentials.
|
|
868
|
+
|
|
869
|
+
## Five tools were unusable in VS Code, and had been since 0.7.0's camera work — 2026-09-12
|
|
870
|
+
|
|
871
|
+
- `kiln_render`, `kiln_edit`, `kiln_inspect`, `kiln_view_interior` and
|
|
872
|
+
`kiln_screenshot_animation` all carried a `z.tuple` camera vector. Zod renders that as
|
|
873
|
+
JSON Schema 2020-12: `prefixItems` plus **`items: false`**, meaning "nothing beyond the
|
|
874
|
+
listed positions". VS Code's tool validator tests `items` for truthiness, so `false`
|
|
875
|
+
reads to it as an array with no items and it refuses to register the tool:
|
|
876
|
+
*"Failed to validate tool mcp_kiln_kiln_edit: tool parameters array type must have
|
|
877
|
+
items."* That is the whole authoring loop — no render, no edit.
|
|
878
|
+
- **Not a regression, and not broken anywhere else.** The tuple arrived with the camera
|
|
879
|
+
capture work in `b2eff76` (2026-09-05) and never changed. Claude Code, opencode 1.18.30
|
|
880
|
+
and the Copilot **CLI** 1.0.83 all register 13 of 13; only VS Code Copilot Chat rejects
|
|
881
|
+
any. The two Copilot surfaces disagree with each other.
|
|
882
|
+
- **Kiln was the conformant party.** SEP-1613 is Final: 2020-12 is the default dialect and
|
|
883
|
+
*"Clients MUST support at least JSON Schema 2020-12"*. The fix is still worth taking,
|
|
884
|
+
because tuples are the one construct the two dialects spell irreconcilably — draft-07
|
|
885
|
+
uses `items: [...]`, 2020-12 uses `prefixItems` + `items: false` — while a bounded
|
|
886
|
+
uniform array (`items: {type: number}` with `minItems`/`maxItems`) is valid and
|
|
887
|
+
identical in both. Choosing it removes a class of client incompatibility rather than
|
|
888
|
+
patching one client.
|
|
889
|
+
- It also made the surface smaller: the `tools/list` frame went **33,937 B to 32,081 B**,
|
|
890
|
+
about 464 tokens saved once per session for every harness, and `docs/tools.md` lost 288
|
|
891
|
+
lines of tuple boilerplate.
|
|
892
|
+
- The tuple TypeScript type is preserved by a static assertion, so nothing downstream
|
|
893
|
+
needed a cast. It is deliberately not a zod `.transform`: that reads as equivalent and
|
|
894
|
+
**breaks every non-MCP harness**, because the Strands skin converts with `io: 'output'`
|
|
895
|
+
where zod refuses — "Transforms cannot be represented in JSON Schema" — while the MCP
|
|
896
|
+
SDK converts with `io: 'input'` and never sees it. Only the in-process parity test
|
|
897
|
+
caught that.
|
|
898
|
+
- Confirmed in the client that rejected them: before the fix VS Code logged the error 26
|
|
899
|
+
seconds after our server connected; after it, all 13 `mcp_kiln_*` tools list, `kiln_edit`
|
|
900
|
+
included. Copilot Chat logs only validation failures and never successes, so this rests
|
|
901
|
+
on the before/after, not on a passing log line.
|
|
902
|
+
- Gated two ways: no array in any advertised schema may have a falsy `items`, and a camera
|
|
903
|
+
vector must still reject two, four, and non-numeric members at runtime. The second gate
|
|
904
|
+
exists because the first one alone would pass on a schema that had quietly become an
|
|
905
|
+
unbounded number list.
|
|
906
|
+
|
|
907
|
+
## Asset links now say how big they are and who they are for — 2026-09-12
|
|
908
|
+
|
|
909
|
+
- A user reported "massive token usage" from VS Code Copilot, attributing it to
|
|
910
|
+
`resource_link` mishandling. Measuring first: `kiln_save`/`kiln_export` put **941 B of
|
|
911
|
+
URIs** on the wire and no file bytes, and a JSON-RPC tap showed the Copilot **CLI**
|
|
912
|
+
never calls `resources/read` at all. So the stated mechanism does not exist in our
|
|
913
|
+
responses — but the report was standing next to something real.
|
|
914
|
+
- Kiln emitted only four of `ResourceLink`'s fields. The spec also carries **`size`** and
|
|
915
|
+
**`annotations.audience`**, which are exactly how a server tells a client "this artifact
|
|
916
|
+
is for the human to download, not for the model to read". Emitting neither left every
|
|
917
|
+
client guessing from a MIME type, including the ones that guess "inline everything".
|
|
918
|
+
Both are now set, with `priority`: `asset.glb` and `preview.png` are `['user']` because
|
|
919
|
+
the model already receives rendered views as image blocks and geometry as metrics;
|
|
920
|
+
`source.kiln.js` is addressed to both.
|
|
921
|
+
- `editable.zip` is no longer advertised. It is a bundle of the files listed beside it, so
|
|
922
|
+
a client resolving every link paid for the same bytes twice — and it was the largest
|
|
923
|
+
entry while being the only derived one. It stays readable at its URI (which is what the
|
|
924
|
+
widget's download button uses) and stays in `downloadUrls`.
|
|
925
|
+
- Net wire cost went **941 B → 1,017 B**. This is not a size win and is not claimed as
|
|
926
|
+
one: it trades 76 bytes for every client being *able* to decide correctly. The `size` is
|
|
927
|
+
compared in the test against the bytes `resources/read` actually returns for that URI,
|
|
928
|
+
because a declared size a client cannot trust is worse than no size at all.
|
|
929
|
+
|
|
930
|
+
## Post-release polish: the install guide had gone stale — 2026-09-12
|
|
931
|
+
|
|
932
|
+
- `docs/install.md` told readers to use a checkout **"until an updated package is
|
|
933
|
+
released"**, naming `kiln-engine-0.6.0.tgz`, an eight-tool surface, and five tools the
|
|
934
|
+
package lacked. All three were true when written and none survived `v0.7.0`. Verified by
|
|
935
|
+
driving the published tarball's MCP server over stdio: it advertises **13 tools**,
|
|
936
|
+
including all five that section said were missing.
|
|
937
|
+
- Rewritten to link the latest release and the generated tool reference instead of
|
|
938
|
+
restating either. The section was fragile because it duplicated facts that live in gated
|
|
939
|
+
files — `docs/tools.md` is already checked against the registry, so it does not need
|
|
940
|
+
repeating in prose that nothing checks.
|
|
941
|
+
- A test now enforces the rule that follows: install guidance may not hard-code a release
|
|
942
|
+
tarball version, and must point at `releases/latest` and `tools.md`. Scoped to the docs
|
|
943
|
+
that tell a reader how to *obtain* the package; `CONTRIBUTING.md` keeps its
|
|
944
|
+
`kiln-engine-0.6.0.tgz` because there the filename is the evidence for why the version
|
|
945
|
+
policy exists. Both failure modes verified — a pinned version, and a link that stops
|
|
946
|
+
pointing at the latest release.
|
|
947
|
+
- `docs/migration.md` said "keeps the package version at `0.6.0` until release review",
|
|
948
|
+
which stopped being true at the tag.
|
|
949
|
+
- **AGENTS.md now explains the two tool surfaces**, which was a real comprehension trap:
|
|
950
|
+
`registry.ts` holds the in-process loop's four tools and the MCP surface's thirteen, and
|
|
951
|
+
"both skins consume it" read as one shared list. The one differing name,
|
|
952
|
+
`kiln_screenshot`, is **merged rather than missing** — in-process, `kiln_render` returns
|
|
953
|
+
metrics only and `kiln_screenshot` carries the six-view grid, so a cheap structural check
|
|
954
|
+
need not pay for an image; on MCP, `kiln_render` is unified and returns metrics, part
|
|
955
|
+
paths and images together, so a separate screenshot tool would be a second way to ask for
|
|
956
|
+
the same grid.
|
|
957
|
+
- Also measured while checking the new-developer path, in a fresh clone: **~31 seconds from
|
|
958
|
+
nothing to a rendered GLB** (4s clone, 26s install, 1s render), and the documented
|
|
959
|
+
render-service step works verbatim — `npm --prefix render-service ci --ignore-scripts` in
|
|
960
|
+
2s, then 37 tests pass.
|
|
961
|
+
|
|
962
|
+
## The Windows failure was a real bug in the alias lock — 2026-09-12
|
|
963
|
+
|
|
964
|
+
- `rejects lost updates from eight independent processes` went red once on a Windows
|
|
965
|
+
runner. The first read of it here was wrong, and the number that refutes it was in the
|
|
966
|
+
log all along: **the test failed in 123 ms**, while both hang guards are 10 and 15
|
|
967
|
+
seconds away. Nothing was slow. A worker died, fast.
|
|
968
|
+
- The only way `compareAndSet` does that is the `throw error` beside its lock, reached
|
|
969
|
+
whenever `mkdir` reports contention with a code other than `EEXIST`. **Windows has
|
|
970
|
+
exactly that case**: directory deletion is not synchronous, so a directory whose last
|
|
971
|
+
handle has not closed sits in pending-delete, where `mkdir` on that name answers `EPERM`
|
|
972
|
+
or `EACCES`. Every release runs `rmdir` in a `finally`, so with eight processes
|
|
973
|
+
contending, one landing in that window is ordinary contention — and it was rethrown.
|
|
974
|
+
- `isLockContention` now recognises those two codes **on Windows only**. Widening it to
|
|
975
|
+
every platform would be the over-fix: on POSIX, `EPERM`/`EACCES` from `mkdir` means the
|
|
976
|
+
parent directory is not writable, and swallowing that would report a permission fault as
|
|
977
|
+
"busy". Both mistakes are pinned by tests — reverting to `EEXIST`-only fails the Windows
|
|
978
|
+
case, over-widening fails the POSIX guard.
|
|
979
|
+
- Lock release stopped being able to decide the call's outcome. `rmdir` has no `force`, and
|
|
980
|
+
on Windows it can fail while a scanner holds the directory — which inside a `finally`
|
|
981
|
+
would replace a precise `Alias conflict` with an unrelated errno, or turn a successful
|
|
982
|
+
write into a failure. Cleanup failures are now swallowed, and a lingering lock degrades
|
|
983
|
+
to "busy" rather than corrupting anything.
|
|
984
|
+
- Asserted on the decision rather than through a real Windows filesystem, so a Linux host
|
|
985
|
+
checks every branch and the platform is a parameter. The worker timings added alongside
|
|
986
|
+
are what made the failure legible in the first place, and they stay: one `FAILED` beside
|
|
987
|
+
seven fast children points at the code, where all eight slow points at the host.
|
|
988
|
+
|
|
989
|
+
## `--receipt` was relative to the wrong directory — 2026-09-12
|
|
990
|
+
|
|
991
|
+
- `scripts/verify-package-receipt.mjs` resolved `--receipt` against `--root` rather than the
|
|
992
|
+
working directory. Those are **the same directory in the CI step**, which is why the
|
|
993
|
+
original passed its own tests and every CI run — and different everywhere else.
|
|
994
|
+
- Found by using it. Assembling the release from downloaded artifacts puts the receipts in
|
|
995
|
+
a staging directory while `root` is the repository, so every path silently became
|
|
996
|
+
`<repo>/linux-package.json` and all four verifications failed with `ENOENT`. The
|
|
997
|
+
assembly refused to publish, which is what it is for.
|
|
998
|
+
- A path a person types on a command line belongs to where they typed it. `root` now
|
|
999
|
+
locates `package.json` and nothing else.
|
|
1000
|
+
- The test that passed while the bug existed is the finding worth keeping: its fixture had
|
|
1001
|
+
`root` and the receipt in the same temp directory, mirroring the CI step, so it could not
|
|
1002
|
+
tell the two rules apart. It now addresses the receipt explicitly and a second case pins
|
|
1003
|
+
the resolution rule with `root` and the receipt in *different* directories. Both fail if
|
|
1004
|
+
the old behaviour is reintroduced — the doubled path in the error is its signature.
|
|
1005
|
+
|
|
1006
|
+
## webgpu 0.6.1 is held out of 0.7.0 — 2026-09-12
|
|
1007
|
+
|
|
1008
|
+
- The bump was slated for this release and then held, because reading what is in it
|
|
1009
|
+
changed the decision. `webgpu@0.6.1` was published **the same day**, and
|
|
1010
|
+
`v0.6.0...v0.6.1` bumps the `third_party/dawn` submodule to "latest" alongside a real
|
|
1011
|
+
fix — unmapping a device's buffers when the device is destroyed, with 114 lines of new
|
|
1012
|
+
tests upstream.
|
|
1013
|
+
- The fix is worth having: render-service creates and destroys a device per capture, and
|
|
1014
|
+
buffer unmapping on destroy is the readback path. That is not what holds it.
|
|
1015
|
+
- What holds it is that **nothing here can exercise it.** CI installs render-service with
|
|
1016
|
+
`--ignore-scripts` so the 37 pure tests run without a device — which means they prove
|
|
1017
|
+
the package resolves and nothing more. `render-service/src/`, `package.json` and
|
|
1018
|
+
`package-lock.json` all ship inside the engine tarball, so an untested native bump would
|
|
1019
|
+
be in the release artifact, attested by four receipts that never touched a GPU.
|
|
1020
|
+
- So 0.7.0 ships from what CI has fully proven, and this is the first change after it,
|
|
1021
|
+
gated on the GPU smoke that already holds Phase 4 §7 and the two conformance runs.
|
|
1022
|
+
- Noted while looking, not changed: `render-service/package.json` has an `allowScripts`
|
|
1023
|
+
field keyed `{"webgpu@0.6.0": true}` that **nothing reads** — not Bun's
|
|
1024
|
+
`trustedDependencies`, no `@lavamoat/allow-scripts` in the tree, and the README says
|
|
1025
|
+
plain `npm install`, which runs scripts anyway. It looks like a control over native
|
|
1026
|
+
build execution and is not one. Left for a deliberate decision rather than deleted.
|
|
1027
|
+
|
|
1028
|
+
## All four platform receipts come from CI now — 2026-09-12
|
|
1029
|
+
|
|
1030
|
+
- The 2026-09-05 release attached `linux-package.json` and `windows-package.json`, but
|
|
1031
|
+
`test:package` ran only in the macOS job — so two of the four platforms a release
|
|
1032
|
+
attests to had **no reproducible source** and were produced by hand. `linux-package`
|
|
1033
|
+
and `windows-package` jobs close that; CI now emits the tarball and all four receipts
|
|
1034
|
+
from one run.
|
|
1035
|
+
- The receipt check left the workflow. It was a ~400-character `node -e` one-liner inside
|
|
1036
|
+
the macOS job, which is tolerable at one platform and not at four: the expected platform
|
|
1037
|
+
differs per job, so copying it is three chances to assert `darwin` on a Linux runner and
|
|
1038
|
+
have the receipt pass anyway. **A receipt that cannot fail is not evidence.** It is now
|
|
1039
|
+
`scripts/verify-package-receipt.mjs`, one line in each of the four jobs.
|
|
1040
|
+
- Extracting it bought two things beyond deduplication. Expected Node and npm versions
|
|
1041
|
+
come from `engines` rather than being written a second time, so `check-toolchain.mjs`
|
|
1042
|
+
stays the single source; and because the receipt records `engineVersion`, each platform
|
|
1043
|
+
receipt is now checked against `package.json` — so a release's receipts are tied to its
|
|
1044
|
+
version rather than merely sitting beside it.
|
|
1045
|
+
- `--tarball` overrides the path the receipt recorded, which is what makes one verifier
|
|
1046
|
+
serve both uses. In the job the receipt names a tarball sitting right there. At
|
|
1047
|
+
release-assembly time the receipts are downloaded artifacts whose absolute paths belong
|
|
1048
|
+
to a runner that no longer exists — but their `tarballSha256` is exactly what must be
|
|
1049
|
+
checked against the file about to be published.
|
|
1050
|
+
- Verified against a real receipt rather than only fixtures: the Linux smoke was run on a
|
|
1051
|
+
Linux host first (16 checks, `engineVersion 0.7.0`), then that receipt was accepted,
|
|
1052
|
+
**rejected when asked to assert `darwin`** — the precise bug copying the one-liner would
|
|
1053
|
+
have caused — and rejected again after one byte was appended to the tarball, naming both
|
|
1054
|
+
hashes.
|
|
1055
|
+
- `REQUIRED_CHECKS` goes to eight, and the gate added two changes ago is what forced that
|
|
1056
|
+
edit: adding a job without deciding whether it gates a merge fails the suite. First time
|
|
1057
|
+
one of this phase's gates caught the next change instead of a past one.
|
|
1058
|
+
|
|
1059
|
+
## 0.7.0 — the version moves with what ships — 2026-09-12
|
|
1060
|
+
|
|
1061
|
+
- `version` sat at `0.6.0` from the OSS release through **21 shipped changes**, while CI
|
|
1062
|
+
named every tarball from it. Two people could hold `kiln-engine-0.6.0.tgz` and have
|
|
1063
|
+
materially different software — across a three.js major, a history rewrite and a `dist/`
|
|
1064
|
+
re-add. It moves per shipped change now: patch for a fix, minor for changed or added
|
|
1065
|
+
capability, which is the normal case pre-1.0.
|
|
1066
|
+
- **0.7.0 rather than a patch.** What accumulated is behaviour: three.js r186, the
|
|
1067
|
+
CommonJS removal it exposed, 128 lines of previously understated tool schema in
|
|
1068
|
+
`docs/tools.md`, and a `shadows.type` contract that now selects a filter from
|
|
1069
|
+
`basic`/`pcf`/`vsm` instead of naming one that no longer exists.
|
|
1070
|
+
- A bump has to be rebuilt, because `runtimeBuildIdentity` hashes the version into each
|
|
1071
|
+
entry's `identity` in `dist/build.json` — the value a build receipt cites. A test now
|
|
1072
|
+
asserts `package.json` and every `dist/build.json` entry agree.
|
|
1073
|
+
- **Nothing caught that drift before, and this was verified rather than assumed.** With
|
|
1074
|
+
the version at 0.7.0 and `dist/` still recording 0.6.0, the full suite passed — 1860
|
|
1075
|
+
tests, zero failures. `mcp-bundle.test.ts` rebuilds `dist/mcp-server.mjs` and compares
|
|
1076
|
+
bytes, but the version is read from `package.json` at runtime rather than inlined, so
|
|
1077
|
+
the bytes are identical and the stale record is invisible to it. Confirmed by the
|
|
1078
|
+
rebuild: `dist/build.json` was the only file that changed.
|
|
1079
|
+
|
|
1080
|
+
## The documented offline gate did not run two of the repository's checks — 2026-09-12
|
|
1081
|
+
|
|
1082
|
+
- `bun run test` is `bun test src scripts`, so it never reached `render-service/`. Its 37
|
|
1083
|
+
tests ran only in CI, in the job 13.7 added — so a contributor editing that subsystem
|
|
1084
|
+
got **no local signal at all** and found out from a red pull request. `check:skills`
|
|
1085
|
+
was the same shape in the other direction: a step in CI's `checks` job that the
|
|
1086
|
+
documented gate never named.
|
|
1087
|
+
- The subsystem cannot fold into `bun test src scripts`: it is a separate npm project
|
|
1088
|
+
with its own lockfile and a native dependency. It gets `bun run test:render-service`
|
|
1089
|
+
instead, which needs `npm --prefix render-service ci --ignore-scripts` once. All 37
|
|
1090
|
+
tests are pure — framing arithmetic, PNG readback packing, cache identity, contract and
|
|
1091
|
+
preset validation — so none needs a GPU or the Dawn build, which is the CI job's own
|
|
1092
|
+
recorded reason `--ignore-scripts` suffices.
|
|
1093
|
+
- Both are now in the gate in `AGENTS.md` and `CONTRIBUTING.md`, and a test asserts the
|
|
1094
|
+
general defect rather than the instance: **every `bun run` command the agent guide
|
|
1095
|
+
names must exist as a script**, and the two that were missing must appear in the gate
|
|
1096
|
+
block itself.
|
|
1097
|
+
- Reading the fenced block rather than the whole file is what makes that discriminate.
|
|
1098
|
+
The first version checked "named anywhere in `AGENTS.md`" and stayed green when the
|
|
1099
|
+
line was deleted from the gate — because the prose underneath mentions the same
|
|
1100
|
+
command. Verified three ways after narrowing: a guide naming a script that does not
|
|
1101
|
+
exist, the line dropped from the block, and the script removed from `package.json` all
|
|
1102
|
+
fail.
|
|
1103
|
+
|
|
1104
|
+
## Three CI jobs reported and blocked nothing — 2026-09-12
|
|
1105
|
+
|
|
1106
|
+
- `build portable Node package` and both `Node package · macOS` jobs run on every push
|
|
1107
|
+
and every pull request, and were required by nothing. Measured before changing
|
|
1108
|
+
anything: **24 of 24 green across the last 8 runs on main**, and a pull request that
|
|
1109
|
+
broke macOS packaging would still have merged.
|
|
1110
|
+
- The test named `every CI job blocks; none of them merely reports` was green throughout,
|
|
1111
|
+
because it checked only `continue-on-error` — the narrower of the two ways a job can
|
|
1112
|
+
fail to block. Its own comment already described the gap it did not cover: *"the other
|
|
1113
|
+
half is a GitHub setting."* For three jobs that setting had simply never been made.
|
|
1114
|
+
- 13.4 set the precedent that a context is required only once it has reported, since a
|
|
1115
|
+
required context that never reports blocks every merge instead of guarding it. It
|
|
1116
|
+
promoted the Windows job on nine runs with seven green; these three clear that bar.
|
|
1117
|
+
- The test now derives every context `ci.yml` can produce — expanding the macOS matrix
|
|
1118
|
+
into its two legs, because GitHub requires the expanded name — and compares it against
|
|
1119
|
+
the list that has to be required. Adding a job without deciding whether it gates a
|
|
1120
|
+
merge now fails the suite. Verified three ways: a new job, a renamed job, and a dropped
|
|
1121
|
+
matrix leg each fail, naming the exact context gained or lost.
|
|
1122
|
+
- **`build the gallery` is deliberately not required.** `pages.yml` is path-filtered, so
|
|
1123
|
+
it stays silent on any pull request touching none of `examples/`, `site/`, `src/`,
|
|
1124
|
+
`scripts/authorship.ts` or `README.md`. Requiring it would block every such merge —
|
|
1125
|
+
the exact trap 13.4 named. The rule is now written down: unconditional workflow,
|
|
1126
|
+
required; conditional workflow, unrequired.
|
|
1127
|
+
|
|
1128
|
+
## The documented way to convert an old clone did not work — 2026-09-12
|
|
1129
|
+
|
|
1130
|
+
- The 2026-09-10 rewrite moved `refs/tags/oss-2026-09-05` as well as `main`, and a tag
|
|
1131
|
+
is the one ref `git fetch` will not update on its own. So the README's remedy
|
|
1132
|
+
— `git fetch origin && git reset --hard origin/main` — left the old tag in place,
|
|
1133
|
+
holding every removed file reachable. Measured on the clone this was found in:
|
|
1134
|
+
`.git` at 228 MB where a fresh clone is 26 MB, with identical content.
|
|
1135
|
+
- Reproduced by running the documented commands verbatim in a throwaway copy. The two
|
|
1136
|
+
obvious next guesses are not merely ineffective, they are **refused**: plain
|
|
1137
|
+
`git fetch --tags` and even `--prune-tags` both report `would clobber existing tag`,
|
|
1138
|
+
so a reader has no route to the answer without already knowing `--force`.
|
|
1139
|
+
- The instructions now force the tag and then reclaim. Verified end to end on the real
|
|
1140
|
+
stale clone: 228 MB to 23 MB, `fsck` clean, `HEAD` and the working tree hash
|
|
1141
|
+
byte-identical before and after. The plan document already recorded that "the tag was
|
|
1142
|
+
the whole rewrite" for the *push* side; this is the same fact on the clone side, which
|
|
1143
|
+
is the side a reader is on.
|
|
1144
|
+
- `scripts/reliability.test.mjs` pins it, and asserts the **absence** of the broken form
|
|
1145
|
+
as well as the presence of the working one — the short version is what a later
|
|
1146
|
+
simplification reaches for.
|
|
1147
|
+
- Clone figures re-measured: 60 MB full and 49 MB with `--filter=blob:none`, where the
|
|
1148
|
+
README said 52 MB and 48 MB. `.git` grew from 18 MB to 26 MB when the runtime bundles
|
|
1149
|
+
were re-added after the rewrite; the checkout is unchanged at 34 MB. The timing claims
|
|
1150
|
+
are removed rather than restated — they are network-bound and cannot be honestly
|
|
1151
|
+
re-verified from a different link.
|
|
1152
|
+
|
|
1153
|
+
## Skill bytes are canonical, and the SEP-2640 record is corrected — 2026-09-12
|
|
1154
|
+
|
|
1155
|
+
- Re-read SEP-2640 from the spec text on its PR branch and the working group's own
|
|
1156
|
+
repository, rather than from a page about it. Three things this project had recorded
|
|
1157
|
+
were wrong.
|
|
1158
|
+
- **The design changed, and not cosmetically.** The extension defines `skills/list`,
|
|
1159
|
+
`skills/get`, and an optional `resources/directory/read`. **`skills/activate` is
|
|
1160
|
+
gone**, and with it the bundle, the scoped tools revealed on activation, and
|
|
1161
|
+
progressive disclosure inside the protocol. The SEP now "defines only the transport
|
|
1162
|
+
binding" and delegates the format and disclosure model to the Agent Skills
|
|
1163
|
+
specification.
|
|
1164
|
+
- **The status heuristic was backwards.** The note here said "read the labels, not the
|
|
1165
|
+
prose", after a summary twice reported the SEP as Final. The SEP document's own
|
|
1166
|
+
`Status:` field *does* read Final; the pull request's label still reads `draft`, and
|
|
1167
|
+
under the SEP process the document is the status of record. The note pointed at the
|
|
1168
|
+
weaker signal.
|
|
1169
|
+
- **"Nothing to build against" is no longer true.** The spec depends on nothing beyond
|
|
1170
|
+
base Resources, capability declaration rides SEP-2133, and the pinned
|
|
1171
|
+
`@modelcontextprotocol/sdk@1.30.0` already carries `extensions` in
|
|
1172
|
+
`ServerCapabilitiesSchema` while `setRequestHandler` takes any schema. Conformance
|
|
1173
|
+
tests merged 2026-09-11.
|
|
1174
|
+
- 7.12 still waits, for a different and checkable reason: **nothing public consumes it.**
|
|
1175
|
+
The TypeScript SDK's convenience wrappers PR is closed unmerged, every public host is a
|
|
1176
|
+
prototype in one contributor's forks, Claude Code's is internal and not public, and the
|
|
1177
|
+
GitHub MCP server prototype is closed. Shipping it now adds a third transport no host
|
|
1178
|
+
can call. **Re-check the TypeScript SDK, not the SEP's status.**
|
|
1179
|
+
- The re-read found one real gap. `skills/list` publishes a per-file `digest` and `size`
|
|
1180
|
+
over raw bytes, and this project already publishes sha256 digests of skill artifacts at
|
|
1181
|
+
`/.well-known/agent-skills/index.json` — but `skills/**` was `-text` in
|
|
1182
|
+
`.gitattributes` and carried the same accidental line-ending mix found in
|
|
1183
|
+
`render-service/src`: five files fully CRLF, two mixed, seven LF. It went unnoticed
|
|
1184
|
+
because the frontmatter parser is tolerant of both. Tolerant parsing is right;
|
|
1185
|
+
publishing a digest over whichever ending an editor happened to write is not.
|
|
1186
|
+
- Normalized to LF across `skills/` and both registry copies, and `check:skills` now
|
|
1187
|
+
rejects CRLF in any skill file. Verified by reintroducing one — and then by `git
|
|
1188
|
+
checkout` restoring the pre-normalization bytes and the gate firing on that too, which
|
|
1189
|
+
is the regression path that actually happens.
|
|
1190
|
+
- Two pieces of the eventual work are already in place: the digest derivation extends
|
|
1191
|
+
7.13's rather than being invented, and `check:skills` has enforced the SEP's
|
|
1192
|
+
name-equals-directory rule since Phase 7.
|
|
1193
|
+
|
|
1194
|
+
## The published tool reference is correct again — 2026-09-12
|
|
1195
|
+
|
|
1196
|
+
- `docs/tools.md` is generated from the tool registry, and `docs/` is in the package's
|
|
1197
|
+
`files` list — so a stale reference is not an internal note being wrong, it is shipped
|
|
1198
|
+
to every install. It was stale: regenerating moved **128 lines**.
|
|
1199
|
+
- The cause was an in-range dependency bump. `zod` 4.4.3 → 4.6.2 changed
|
|
1200
|
+
`z.toJSONSchema` to emit `items: false`, `minItems` and `maxItems` for fixed-length
|
|
1201
|
+
tuples, so every tuple input in the published reference understated its own schema.
|
|
1202
|
+
- Nothing caught it because the generator's `--check` mode appeared in **no workflow and
|
|
1203
|
+
no test** — the same shape as the render service's 37 tests running nowhere. An
|
|
1204
|
+
offline gate that runs nowhere is worth exactly as much as no gate.
|
|
1205
|
+
- It is a test now rather than a workflow step: the generator exports
|
|
1206
|
+
`toolReferenceMarkdown()` with its CLI behaviour behind a direct-entry guard, and
|
|
1207
|
+
`scripts/tool-reference.test.mjs` compares the published file to the registry. `bun
|
|
1208
|
+
test` already runs on Linux, Windows and both macOS architectures, so this needs no
|
|
1209
|
+
new job — and cannot become a job somebody forgets to add, which is the failure mode
|
|
1210
|
+
being fixed.
|
|
1211
|
+
- Compared whole rather than section by section: the drift that shipped was four added
|
|
1212
|
+
lines inside one nested schema, which any summary comparison would have missed.
|
|
1213
|
+
Verified by dropping a single `minItems` line and watching the test name the file and
|
|
1214
|
+
the command that fixes it.
|
|
1215
|
+
|
|
1216
|
+
## Every directory that holds code is linted now — 2026-09-12
|
|
1217
|
+
|
|
1218
|
+
- 14.4 left the one-off tools in `scripts/` out and priced the alternative at 26 lint
|
|
1219
|
+
findings, a 1,530-line reflow, and 162 lines of coverage slack. After the ratchet got
|
|
1220
|
+
a scope the third term is **zero** — `scripts/**` is not instrumented at all — so what
|
|
1221
|
+
was left was a diff, and it is taken. **480 files where 442 were.**
|
|
1222
|
+
- Thirty-four format findings and thirty-two real ones, over `.mjs` and `.ts` alike; the
|
|
1223
|
+
`.ts` files under `scripts/` had never been linted either, since the pattern was
|
|
1224
|
+
`src/**/*.ts`.
|
|
1225
|
+
- Twenty-five `useTemplate`, seventeen of them one idiom: `JSON.stringify(…) + '\n'`,
|
|
1226
|
+
the receipt-file shape, across eleven files. A shared helper is the obvious DRY move
|
|
1227
|
+
and is deliberately not taken — `package-plugin.mjs` ships in the package `files`
|
|
1228
|
+
list, so importing one means shipping another file for a cosmetic win.
|
|
1229
|
+
- Three findings were not cosmetic. **Two `any` in the pilot evaluation host**: one read
|
|
1230
|
+
as `previous.config` / `previous?.deadline`, now typed; one feeding a budget estimator
|
|
1231
|
+
through optional chains, now a declared `PilotToolInput` that names exactly the fields
|
|
1232
|
+
the image-cell budget depends on — documentation the estimator did not have. A loop's
|
|
1233
|
+
update step hiding in its condition in `smoke-package.mjs`. And **a literal ESC byte**
|
|
1234
|
+
in `harness.mjs`'s ANSI stripper, invisible in every diff and editor, now `\u001B`.
|
|
1235
|
+
- Also surfaced, and deliberately left for its own change: `docs/tools.md` is stale and
|
|
1236
|
+
its `docs:tools --check` drift checker runs in no workflow and no test. The cause is
|
|
1237
|
+
the `zod` 4.4.3 → 4.6.2 bump — `z.toJSONSchema` now emits `items: false`, `minItems`
|
|
1238
|
+
and `maxItems` for fixed-length tuples — so the published tool reference has
|
|
1239
|
+
understated every tuple schema since. Ledger 14.8.
|
|
1240
|
+
|
|
1241
|
+
## render-service joins the lint surface — 2026-09-12
|
|
1242
|
+
|
|
1243
|
+
- It was left out because `render-service/src/**` is `-text` in `.gitattributes` and the
|
|
1244
|
+
formatter would rewrite the line endings. Looking at what the attribute protected
|
|
1245
|
+
turned that reason into the finding.
|
|
1246
|
+
- **It was sweeping, not deliberate.** The line arrived in the OSS release commit
|
|
1247
|
+
alongside the other `-text` entries, and what it froze is inconsistent: four files
|
|
1248
|
+
fully CRLF, `renderer.mjs` at 395 of 399 lines, three carrying a single stray CRLF
|
|
1249
|
+
line, four fully LF. One stray CRLF line in an otherwise-LF file is an editor's
|
|
1250
|
+
signature, not a decision.
|
|
1251
|
+
- **Those bytes are genuinely hashed**, so the replacement matters:
|
|
1252
|
+
`fingerprintRendererInputs` walks that directory into the renderer's capture identity.
|
|
1253
|
+
But `-text` only guarantees "whatever was committed", while the `* text=auto eol=lf`
|
|
1254
|
+
rule guarantees what the fingerprint needs — one line ending on every platform. The
|
|
1255
|
+
normalization is a stricter guarantee than the attribute it replaces.
|
|
1256
|
+
- **Nothing re-validates the old digest.** `capture-producer.v1` fingerprints in
|
|
1257
|
+
checked-in provenance receipts record the renderer build a poster was made under; no
|
|
1258
|
+
test recomputes one. 13.6 already edited two of these files and every gate stayed
|
|
1259
|
+
green — a later build hashing differently is the point of recording it.
|
|
1260
|
+
- Eight files to LF, the attribute removed with the reasoning left where the next reader
|
|
1261
|
+
will ask, and the directory linted: **442 files where 416 were.** Twenty-two format
|
|
1262
|
+
findings, then five real ones. One of them, `useIterableCallbackReturn` in
|
|
1263
|
+
`presentation-presets.mjs`, is the same defect 13.5 fixed in the Bradley-Terry fit —
|
|
1264
|
+
a one-expression arrow in a `forEach` returning a value the contract discards — sitting
|
|
1265
|
+
in production render-service code that was outside every lint gate this repo has.
|
|
1266
|
+
- `reliability.test.mjs` pins both include patterns and asserts the `-text` line stays
|
|
1267
|
+
gone. render-service's own 37 tests pass on the normalized sources.
|
|
1268
|
+
|
|
1269
|
+
## The coverage ratchet has a scope now — 2026-09-12
|
|
1270
|
+
|
|
1271
|
+
- The previous entry blamed 162 lines of lost coverage slack on helper scripts being
|
|
1272
|
+
measured and never executed. The number was right; the mechanism was wrong. Bun
|
|
1273
|
+
instruments only files it loads, and `coveragePathIgnorePatterns` already dropped
|
|
1274
|
+
`**/*.test.mjs`, so those tools were never in the report — there is no `SF:` record
|
|
1275
|
+
for `dispatch-asset`, `upload-posters`, `geometry-experiments` or `harness`.
|
|
1276
|
+
- Exactly **four** files under `scripts/` were instrumented, because tests import them:
|
|
1277
|
+
`evaluation/observe-shipping.mjs`, `build-runtime.mjs`, `evaluation/conditions.ts` and
|
|
1278
|
+
`authorship.ts`. 229 lines against the engine's 45,726 — 0.5% of the denominator, and
|
|
1279
|
+
worth 0.10 points. Two of the four are dense single-expression files, so reflowing
|
|
1280
|
+
them inflated their line counts while their covered lines stayed put. That is where
|
|
1281
|
+
the 162 lines went.
|
|
1282
|
+
- So the finding is narrower and worse than "helper scripts dilute the ratchet": the
|
|
1283
|
+
engine's coverage contract had a **repo-only formatting input**. A number this
|
|
1284
|
+
repository enforces as policy could be moved by reformatting code that does not ship.
|
|
1285
|
+
- `bunfig.toml` now ignores `scripts/**` for coverage. Those tests still run — they are
|
|
1286
|
+
the gates — but their sources leave the denominator, so the ratchet is a statement
|
|
1287
|
+
about the shipped engine and nothing else. Re-measured on the narrowed scope: **95.39%
|
|
1288
|
+
functions, 92.59% lines**.
|
|
1289
|
+
- Narrowing hands back 44 lines of slack no new test earned, so `lines` goes 92 → **92.1**
|
|
1290
|
+
to hold the 224-line margin 13.3 chose rather than pocket it. `functions` stays at 94,
|
|
1291
|
+
where the margin is unchanged in practice. Tightening further is a separate decision.
|
|
1292
|
+
- And the record carries its own scope now. `measuredBaseline` requires `measuredOver`,
|
|
1293
|
+
the gate refuses a baseline without it, and it prints it: `Recorded baseline:
|
|
1294
|
+
functions 95.39%, lines 92.59% (over src/, bun@1.4.2, 2026-09-12)`. A percentage
|
|
1295
|
+
without its scope is as ambiguous as a threshold without a baseline — which is what
|
|
1296
|
+
made the wrong explanation above plausible enough to write down.
|
|
1297
|
+
|
|
1298
|
+
## The repository's own gates are linted now — 2026-09-12
|
|
1299
|
+
|
|
1300
|
+
- Adding a file to `scripts/` and running `biome check` on its path printed "No files
|
|
1301
|
+
were processed." Biome's `files.includes` was `src/`, `site/src/` and `site/*.ts`, so
|
|
1302
|
+
the directory holding this repository's gates — and which `test:coverage` already
|
|
1303
|
+
measures — sat outside the lint surface. The zero-warning baseline 13.5 established
|
|
1304
|
+
was zero across a subset.
|
|
1305
|
+
- Taken: `scripts/check-*.mjs` and `scripts/**/*.test.mjs` — the checks are now checked.
|
|
1306
|
+
416 files where 405 were. Ten findings were behind the hole: seven format, and three
|
|
1307
|
+
real ones. A dead `const` in `check-vision.mjs`, easy to miss because the identical
|
|
1308
|
+
line two loops down is load-bearing. Two `useTemplate` on the
|
|
1309
|
+
`JSON.stringify(…) + '\n'` idiom. `reliability.test.mjs` asserts both include
|
|
1310
|
+
patterns, verified by dropping one and watching it fail.
|
|
1311
|
+
- Left, with the cost measured rather than guessed. The rest of `scripts/` is one-off
|
|
1312
|
+
tools, several authored as dense single-expression lines. Taking the whole directory
|
|
1313
|
+
is 26 lint findings, a 1,530-line reflow (3,078 lines to 4,608, pure formatting), and
|
|
1314
|
+
**162 lines of coverage slack** — lines fall 92.49% to 92.14% against a threshold of
|
|
1315
|
+
92. Measured by taking the full pass and running the gate.
|
|
1316
|
+
- **Corrected below**: the mechanism first given for that third cost was wrong, and it
|
|
1317
|
+
pointed at the wrong fix.
|
|
1318
|
+
- `render-service/` stays out for an unrelated reason: its sources are CRLF by
|
|
1319
|
+
`.gitattributes`, and the formatter would rewrite the line endings.
|
|
1320
|
+
- One incidental finding: Biome prints at most 20 diagnostics by default, so a count
|
|
1321
|
+
read off `bun run lint` is a floor, not a total. The gate still fails either way.
|
|
1322
|
+
|
|
1323
|
+
## The prompt-cache breakpoint is asserted on the wire — 2026-09-12
|
|
1324
|
+
|
|
1325
|
+
- The two deferred rows in the queue were both deferred *with a reason*. Checking the
|
|
1326
|
+
reasons rather than inheriting them changed both answers.
|
|
1327
|
+
- **The `ai` 7 family is blocked upstream, and money was never the constraint.** The
|
|
1328
|
+
recorded reason was that only `test:live` exercises those paths and it spends money.
|
|
1329
|
+
What actually blocks it: `@strands-agents/sdk@1.17.0` is the latest release, declares
|
|
1330
|
+
peer `@ai-sdk/provider: ^3.0.0`, and types its `VercelModel` on `LanguageModelV3`,
|
|
1331
|
+
while `@openrouter/ai-sdk-provider@3` requires `ai@^7`, which depends on
|
|
1332
|
+
`@ai-sdk/provider@4`. No budget moves that.
|
|
1333
|
+
- And `typecheck` would not have caught it. `@ai-sdk/provider@4` still exports
|
|
1334
|
+
`LanguageModelV3` beside V4, so the import keeps compiling; the break is a v4 model
|
|
1335
|
+
handed to a v3 wrapper, at runtime, on the one path no offline suite drives. There is
|
|
1336
|
+
a gate for it now: `scripts/peer-ranges.test.mjs` walks the installed tree and fails
|
|
1337
|
+
on a peer range the version beside it does not meet.
|
|
1338
|
+
- **It found a mismatch that already exists.** `@strands-agents/sdk` declares peer
|
|
1339
|
+
`@anthropic-ai/sdk: ^0.109.1` — on a 0.x version that means `>=0.109.1 <0.110.0` —
|
|
1340
|
+
and the last dependency refresh took 0.125.0. Fifteen minors past the declared
|
|
1341
|
+
range, moved by a routine in-range update, noticed by nothing. Kept, and listed with
|
|
1342
|
+
its reasoning in the gate's `ACCEPTED` table, so the next one fails while this one is
|
|
1343
|
+
a decision on the record rather than a silence.
|
|
1344
|
+
- **The native cache breakpoint is now asserted against the bytes.** The OpenRouter
|
|
1345
|
+
half already was: it drives `doStream` with `fetch` replaced and reads the outgoing
|
|
1346
|
+
JSON. The native half asserted that `toCachedSystemPrompt` returns
|
|
1347
|
+
`[TextBlock, CachePointBlock]` — the input to the transport, never its output. So the
|
|
1348
|
+
claim the design rests on, that a cache point becomes `cache_control` on the wire,
|
|
1349
|
+
was carried by a comment, on two dependencies that move inside their caret ranges on
|
|
1350
|
+
every refresh. Losing it bills full price for every prefix that should have been a
|
|
1351
|
+
cache read, with every offline gate green.
|
|
1352
|
+
- Both native transports are captured now, offline: the Anthropic client takes a
|
|
1353
|
+
`fetch` that records and throws, Bedrock a `requestHandler` that does the same. Both
|
|
1354
|
+
tests are differential — a plain string goes out with no breakpoint — so the
|
|
1355
|
+
breakpoint has one possible origin. Establishing that took an injected defect, which
|
|
1356
|
+
disproved the first draft's premise: Bedrock does *not* auto-inject a system cache
|
|
1357
|
+
point here, because that needs a `cacheConfig` and Kiln passes none. Patching the
|
|
1358
|
+
installed adapters to drop `cache_control` and the converse `cachePoint` fails
|
|
1359
|
+
exactly the new tests while every pre-existing test stays green — including the one
|
|
1360
|
+
named "the adapter emits `cache_control`", which never checked that it did.
|
|
1361
|
+
- **7.12 / SEP-2640 stays deferred, for a better reason.** PR 2640 is open and still
|
|
1362
|
+
labelled `draft`; a page summary reported it Final for the second time and was wrong
|
|
1363
|
+
again. But the row turns on something downstream: `@modelcontextprotocol/sdk`
|
|
1364
|
+
publishes 1.30.0 as latest, the version already installed, so there is no TypeScript
|
|
1365
|
+
surface for `skill://` resources to build against whatever the SEP does next. Check
|
|
1366
|
+
the SDK's version, not the pull request.
|
|
1367
|
+
|
|
1368
|
+
## A preset's shadow filter now selects a filter — 2026-09-12
|
|
1369
|
+
|
|
1370
|
+
- Going to compare shadow filters by eye turned up the reason there was nothing to
|
|
1371
|
+
compare: **no shipped presentation preset enables shadows.** `neutral-studio-v1` sets
|
|
1372
|
+
`shadows.enabled: false` to preserve the pre-registry visual, `gallery-studio-v1` is a
|
|
1373
|
+
spread of it, and every light has `castsShadow: false`. So r186 deleting the PCFSoft
|
|
1374
|
+
implementation is not a visible regression here, and yesterday's switch to
|
|
1375
|
+
`PCFShadowMap` corrected a line that never runs. Its claim to keep the log clean was
|
|
1376
|
+
overstated: the assignment sits inside `if (preset.shadows.enabled)`, so three's
|
|
1377
|
+
deprecation warning never fired from this service either.
|
|
1378
|
+
- What was actually wrong is that `shadows.type` described a filter and selected nothing.
|
|
1379
|
+
The validator demanded the exact string `pcf-soft` while the renderer ignored the field
|
|
1380
|
+
and hardcoded a constant — and after r186, the one name the schema accepted was the one
|
|
1381
|
+
name that no longer exists.
|
|
1382
|
+
- It selects a filter now. `SHADOW_FILTERS` is `basic`, `pcf`, `vsm` — what r186 left —
|
|
1383
|
+
and the renderer maps each to its three constant. `vsm` is the soft option that
|
|
1384
|
+
survives, with one catch recorded where someone choosing it will read it: under VSM
|
|
1385
|
+
every shadow receiver also casts, so a ground plane starts casting too.
|
|
1386
|
+
- The names live in the schema that validates them and the constants live in the module
|
|
1387
|
+
that imports three, so the renderer checks at load that the map covers the list. A name
|
|
1388
|
+
the validator accepts and the map lacks would set `shadowMap.type` to `undefined` mid
|
|
1389
|
+
render — not a crash, just a quietly different image. Verified by adding `pcf-soft` back
|
|
1390
|
+
to the list and watching the service refuse to start.
|
|
1391
|
+
- The gallery is not affected either, for a different reason: neither `<Canvas>` in the
|
|
1392
|
+
site sets r3f's `shadows` prop, so `renderer.shadowMap.enabled` stays false there too,
|
|
1393
|
+
and the only shadowing on that surface is drei's `ContactShadows` — its own depth pass to
|
|
1394
|
+
a texture, which never consults `shadowMap.type`. Between the two paths, r186's PCFSoft
|
|
1395
|
+
removal changes nothing anyone can see in this repository.
|
|
1396
|
+
- **`render-service` is in CI now**, which it never was. Thirty-seven tests guarding a
|
|
1397
|
+
shipped subsystem ran on nobody's machine but a maintainer's — including, until this
|
|
1398
|
+
commit, the change above it. It is a separate npm project with a native dependency,
|
|
1399
|
+
which is presumably the reason; but the tests do not need it. All 37 are pure: framing
|
|
1400
|
+
arithmetic, PNG readback packing, cache identity, contract and preset validation, and
|
|
1401
|
+
not one acquires a device. So the job installs with `--ignore-scripts`, skipping the
|
|
1402
|
+
`webgpu` package's Dawn build. Verified against exactly that install with no binding
|
|
1403
|
+
built: 37 pass, 0 fail. The GPU smoke and the two conformance runs stay manual, because
|
|
1404
|
+
those genuinely need a device.
|
|
1405
|
+
|
|
1406
|
+
## The lint baseline is zero, and stays zero — 2026-09-12
|
|
1407
|
+
|
|
1408
|
+
- `bun run lint` reported **14 warnings and 11 infos** and exited 0. All 25 are fixed;
|
|
1409
|
+
the tree now reports nothing. The point is not tidiness: a baseline everyone agrees to
|
|
1410
|
+
ignore is a baseline the twenty-sixth finding arrives invisible against.
|
|
1411
|
+
- Two of them were not style. `isFinite` in the render inspector is the coercing global,
|
|
1412
|
+
where `Number.isFinite` is not — identical on a `Box3` component, taken because the next
|
|
1413
|
+
caller to pass something looser is the one the coercion silently accepts. And
|
|
1414
|
+
`ids.forEach((id, i) => index.set(id, i))` in the Bradley-Terry fit returned the map
|
|
1415
|
+
from a callback whose contract discards it; the index is built from its pairs instead.
|
|
1416
|
+
- Three `any` bounds in `buildSandboxGlobals` carried
|
|
1417
|
+
`// eslint-disable-next-line @typescript-eslint/no-explicit-any`. This repository lints
|
|
1418
|
+
with Biome and has no ESLint config, so those suppressed nothing while reading as
|
|
1419
|
+
reviewed-and-accepted. Rather than translate them, the `any` is gone: `never[]` is the
|
|
1420
|
+
correct bound for "any parameter list" and `unknown` for "any return", with one narrow
|
|
1421
|
+
assertion where tsc resolves a call through the constraint and can only see `unknown`.
|
|
1422
|
+
- The quaternion fixture's `0.7071` is now `Math.SQRT1_2` — exact, and it says which angle
|
|
1423
|
+
a quarter turn about Y actually is.
|
|
1424
|
+
- **Warnings now fail.** `lint` runs with `--error-on-warnings`, and because that flag
|
|
1425
|
+
does not reach Biome's info severity — where `useTemplate` and several others sit by
|
|
1426
|
+
default — the seven rules this cleanup touched carry an explicit `error` in
|
|
1427
|
+
`biome.json`. Each of the seven was verified by reintroducing its defect and confirming
|
|
1428
|
+
the gate fails and names the rule.
|
|
1429
|
+
- The `useIterableCallbackReturn: "warn"` downgrade is gone with the finding it was
|
|
1430
|
+
written around. A test asserts the seven severities and the `lint` script itself: a rule
|
|
1431
|
+
lowered to keep a build green is indistinguishable from a rule nobody wanted, and that
|
|
1432
|
+
has happened here before.
|
|
1433
|
+
- `CONTRIBUTING.md` says the contract plainly — the tree reports nothing, so any
|
|
1434
|
+
diagnostic a change produces belongs to that change, to fix or to suppress with a
|
|
1435
|
+
`biome-ignore` comment that says why.
|
|
1436
|
+
|
|
1437
|
+
## The gates stop reporting and start blocking — 2026-09-12
|
|
1438
|
+
|
|
1439
|
+
- **The Windows job blocks.** It landed reporting-only on purpose, because the fault it
|
|
1440
|
+
was added to rule out — a native GLib `g_system_thread_free` / invalid `CloseHandle`
|
|
1441
|
+
inside libvips/sharp under Bun's threading — was intermittent, and a required check
|
|
1442
|
+
that fails at random is worse than no check. Its whole history is now nine runs: seven
|
|
1443
|
+
green, two red, and not one recurrence. Both reds were new code from the session that
|
|
1444
|
+
added the job — a `require('sharp/package.json')` that sharp's `exports` map blocks,
|
|
1445
|
+
and a `new URL('..', import.meta.url).pathname` that yields `/D:/a/kiln/src/` — and
|
|
1446
|
+
neither is reachable from a POSIX host. The failures were true, which is the argument
|
|
1447
|
+
for blocking rather than against it.
|
|
1448
|
+
- Blocking means a hang is a blocked merge rather than a slow report, so the job now has
|
|
1449
|
+
a 30-minute bound. The suite runs there in about two minutes.
|
|
1450
|
+
- A test asserts no CI job carries `continue-on-error` at job level, so this cannot be
|
|
1451
|
+
demoted by one line slipping back in. The single step-level exception is the native
|
|
1452
|
+
dependency inventory, which exists to attach libvips and GLib versions to a run if the
|
|
1453
|
+
fault ever returns and must never be why Windows reports red. Indentation is the
|
|
1454
|
+
distinction and the test reads it as such.
|
|
1455
|
+
- **The coverage ratchet moves to 94% functions / 92% lines**, from 92/91. Measured
|
|
1456
|
+
95.27% and 92.49% on this tree, which leaves 42 functions and 224 lines of room.
|
|
1457
|
+
- That "42 functions" is the other half of the change: the gate now reports its margin
|
|
1458
|
+
in the unit a person can act on. A percentage says whether the gate passed; turning it
|
|
1459
|
+
into work needs LCOV totals that are not in front of whoever tripped it. Slack rounds
|
|
1460
|
+
down and a shortfall rounds up, so neither reads as more comfortable than it is.
|
|
1461
|
+
- The gate also refuses a threshold set above the baseline it records. That is the one
|
|
1462
|
+
mistake the coverage comparison cannot catch by itself: a threshold above anything
|
|
1463
|
+
ever measured fails in whatever change happens to run next, and reads there as that
|
|
1464
|
+
change's regression. A thresholds file with no recorded baseline is refused for the
|
|
1465
|
+
same reason — a ratchet is raised to a number somebody measured.
|
|
1466
|
+
|
|
1467
|
+
## Dependencies current in range, and the toolchain gate gets its own test — 2026-09-12
|
|
1468
|
+
|
|
1469
|
+
- In-range refresh, deliberately kept apart from the deferred majors: `ai` 6.0.222 →
|
|
1470
|
+
6.0.282, `openai` 6.46.0 → 6.49.0, `@ai-sdk/provider` 3.0.14 → 3.0.16,
|
|
1471
|
+
`@aws-sdk/client-bedrock-runtime` 3.1083.0 → 3.1131.0, and in `site/` react and
|
|
1472
|
+
react-dom 19.2.8 → 19.3.0 with their types, plus vite 8.2.2 → 8.3.0.
|
|
1473
|
+
- The `ai` 7 / `@ai-sdk/provider` 4 / `@openrouter/ai-sdk-provider` 3 family stays
|
|
1474
|
+
where it was. Only `test:live` exercises those paths and it spends money, and the
|
|
1475
|
+
deliberate prompt-cache transport asymmetry is exactly what a provider major breaks
|
|
1476
|
+
without a test noticing. Nothing enforces that decision in prose and nothing needs
|
|
1477
|
+
to: the caret ranges cannot resolve to a new major, so the boundary is structural.
|
|
1478
|
+
- The `@types/three` parity rule added yesterday now reads as what it always was — a
|
|
1479
|
+
rule about types, not about three. Every `@types/*` whose runtime package the same
|
|
1480
|
+
manifest pins must sit on that runtime's release line. That is what brought
|
|
1481
|
+
`@types/react` and `@types/react-dom` along with react 19.3: the site compiles its
|
|
1482
|
+
`@react-three/fiber` JSX against those types, and types a release line behind make
|
|
1483
|
+
new API invisible to `tsc` while removed API still typechecks.
|
|
1484
|
+
- **`check-toolchain.mjs` now has a test.** It had grown three times, each extension
|
|
1485
|
+
verified by injecting the defect by hand, once, at the time — the right check made in
|
|
1486
|
+
the wrong place, because nothing stopped a later edit from leaving a rule that could
|
|
1487
|
+
no longer fail. A vacuous gate is worse than no gate, since it is believed. The gate
|
|
1488
|
+
takes an optional `--root`, and each case stages a real copy of the repository's own
|
|
1489
|
+
files, mutates exactly one value, and asserts the gate names it: stale engine pin,
|
|
1490
|
+
prose that installs the wrong Bun, three drifting in either the site or the render
|
|
1491
|
+
service, types off their runtime's line, an Action pinned to a mutable tag, and a
|
|
1492
|
+
Pages workflow left behind. Staging the real files rather than a synthetic fixture is
|
|
1493
|
+
the point: a rule whose phrasing drifts out of step with the document it reads fails
|
|
1494
|
+
the baseline case immediately.
|
|
1495
|
+
- A mutation that changes nothing fails the test. A search string that no longer
|
|
1496
|
+
appears injects no defect, the gate correctly reports a clean tree, and the case goes
|
|
1497
|
+
green having checked nothing — the exact rot the file exists to prevent, so it is
|
|
1498
|
+
caught rather than trusted.
|
|
1499
|
+
|
|
1500
|
+
## The r186 bump missed the site, and now a gate catches that — 2026-09-12
|
|
1501
|
+
|
|
1502
|
+
- `site/` was still on three 0.185.1 while the engine and `render-service` moved to
|
|
1503
|
+
0.186.0. Substantive rather than untidy: kiln emits `EXT_mesh_gpu_instancing`, and
|
|
1504
|
+
r186 fixed that extension's custom instance attribute sharing in `GLTFLoader`, so
|
|
1505
|
+
the site was rendering the gallery with an unfixed loader for an extension the
|
|
1506
|
+
engine writes.
|
|
1507
|
+
- `check:toolchain` now asserts `three` is byte-identical in every manifest that pins
|
|
1508
|
+
it, and that `@types/three` tracks its minor. Verified by injecting three defects —
|
|
1509
|
+
the exact drift that shipped, a `render-service` drift, and a stale `@types/three` —
|
|
1510
|
+
and confirming each is caught and names the offending manifest.
|
|
1511
|
+
- The reason this is a gate and not a note: the same class of defect, a value that
|
|
1512
|
+
must agree across files with nothing enforcing it, had been caught in the prose that
|
|
1513
|
+
same morning by a person. Twice in one day is an argument for a check.
|
|
1514
|
+
|
|
1515
|
+
## Finishing the CommonJS removal the r186 bump started — 2026-09-12
|
|
1516
|
+
|
|
1517
|
+
- The previous entry's fix was incomplete, and looked complete.
|
|
1518
|
+
`src/ops.ts` moved to the ESM build, but `src/__tests__/subdivide-normals.test.ts`
|
|
1519
|
+
still imported the bare specifier — so the CommonJS build kept loading and kept
|
|
1520
|
+
emitting `THREE_CJS_DEPRECATED`, while the production import read as corrected.
|
|
1521
|
+
The whole suite now reports **zero** occurrences of that warning.
|
|
1522
|
+
- `three-subdivide` is pinned **exactly** rather than by caret. The deep path
|
|
1523
|
+
`three-subdivide/build/index.module.js` is legal precisely because the package
|
|
1524
|
+
declares no `exports` map; a minor release that added one would make the path
|
|
1525
|
+
unresolvable, and a caret range would have taken that release silently.
|
|
1526
|
+
- `src/__tests__/three-subdivide-esm.test.ts` guards the whole tree rather than one
|
|
1527
|
+
file, which is the lesson from the partial fix: it walks every `.ts` under `src/`,
|
|
1528
|
+
asserts the ESM build has no `require(` call, and asserts the pin is exact.
|
|
1529
|
+
Verified by injecting the bare specifier into `src/ops.ts` and confirming the guard
|
|
1530
|
+
fails *and names the offending file*, rather than by observing a pass.
|
|
1531
|
+
- Timing, since it reads as urgent and is not: three deprecated the CommonJS build in
|
|
1532
|
+
r186 and has not announced a removal release. Its own precedent — `build/three.js`
|
|
1533
|
+
deprecated at r150, removed at r160 — suggests roughly ten releases of runway. The
|
|
1534
|
+
reason to fix it now is the warning users see today, not the removal.
|
|
1535
|
+
|
|
1536
|
+
## three.js r186, and the CommonJS load it exposed — 2026-09-11
|
|
1537
|
+
|
|
1538
|
+
- `three` and `@types/three` to 0.186.0 in both the engine and `render-service`.
|
|
1539
|
+
The types were the blocker and they shipped; r186's three named breaking changes
|
|
1540
|
+
— `Source` → `TextureSource`, `toTrianglesDrawMode()` mutating in place,
|
|
1541
|
+
`Object3D.dispose()` needing `super.dispose()` — touch nothing here, checked
|
|
1542
|
+
before the bump rather than discovered by it.
|
|
1543
|
+
- **`three-subdivide` was pulling three in through the deprecated CommonJS build.**
|
|
1544
|
+
It has no `exports` map, so a bare specifier resolves to `main`, which is a UMD
|
|
1545
|
+
bundle doing `require("three")`. r186 did not create this; it made it audible, by
|
|
1546
|
+
emitting `THREE_CJS_DEPRECATED` on stderr — which every `kiln` CLI invocation
|
|
1547
|
+
would then have printed. Fixed by importing the ESM build the package already
|
|
1548
|
+
ships, `three-subdivide/build/index.module.js`, which has zero `require(` calls.
|
|
1549
|
+
`three-subdivide@1.1.5` is the latest release, so there is no upstream fix to
|
|
1550
|
+
wait for, and three has announced the CJS build's removal.
|
|
1551
|
+
- Worth recording because it is tempting and wrong: this does **not** fix a
|
|
1552
|
+
dual-THREE instance hazard. `src/primitives.ts` documents one, and it was
|
|
1553
|
+
measured here rather than assumed — geometry from both the CJS and the ESM build
|
|
1554
|
+
satisfies `instanceof THREE.BufferGeometry`. The `isBufferGeometry` flag tests
|
|
1555
|
+
stay, because they are correct defensively regardless.
|
|
1556
|
+
- **The GPU service was requesting a shadow filter that no longer exists.** r186
|
|
1557
|
+
removed the `PCFSoftShadowMap` implementation while keeping the constant; three
|
|
1558
|
+
warns and substitutes `PCFShadowMap`. `render-service` now names the filter it
|
|
1559
|
+
actually gets. Material conformance returns numbers identical in every region
|
|
1560
|
+
before and after, which is the proof the substitution was already happening.
|
|
1561
|
+
- Verified on hardware, not only offline: 1,831 pass / 0 fail, typecheck clean,
|
|
1562
|
+
lint at the unchanged 14/11 baseline, and `material-conformance` `PASS` on
|
|
1563
|
+
`dawn-vulkan` across all six channels. One number to watch —
|
|
1564
|
+
`normalHalfLumaDelta` moved 1.51 → 1.2 against a threshold of 1, consistent with
|
|
1565
|
+
r186's diffuse energy-conservation change. It passes with less margin than 11.5
|
|
1566
|
+
measured, which is an argument for that row's follow-up rather than for a new
|
|
1567
|
+
threshold.
|
|
1568
|
+
|
|
1569
|
+
## The guide was pinning a toolchain the gate rejects — 2026-09-11
|
|
1570
|
+
|
|
1571
|
+
- `AGENTS.md`, `CONTRIBUTING.md`, `README.md`, `docs/google.md` and
|
|
1572
|
+
`docs/install.md` still named Bun 1.3.14, Node 22.23.1 and npm 12.0.1 after the
|
|
1573
|
+
bump to 1.4.2/22.23.2/12.0.2. `AGENTS.md` is the guide every harness reads, so
|
|
1574
|
+
the first command a new contributor ran installed a Bun that
|
|
1575
|
+
`bun run check:toolchain` — the next command in the same list — then rejected.
|
|
1576
|
+
- `scripts/check-toolchain.mjs` now asserts those five documents state the
|
|
1577
|
+
supported triple, and that `pages.yml` pins the same Bun as `ci.yml`. The gate
|
|
1578
|
+
had enforced `package.json` and `ci.yml` and nothing else, so both the prose and
|
|
1579
|
+
the second workflow could drift silently; `pages.yml` was correct today only
|
|
1580
|
+
because it was set by hand in the same change. Verified by injecting each of the
|
|
1581
|
+
three defects and confirming a non-zero exit, rather than by observing a pass.
|
|
1582
|
+
- Dated receipts under `docs/evaluation/` are deliberately excluded from the
|
|
1583
|
+
check. They record the toolchain a run actually used, and rewriting one to match
|
|
1584
|
+
a new pin would falsify it.
|
|
1585
|
+
|
|
1586
|
+
## Skills are fetchable by URL — 2026-09-11
|
|
1587
|
+
|
|
1588
|
+
- The six skills are published at
|
|
1589
|
+
`https://kilnstudio.tools/.well-known/agent-skills/index.json`, per
|
|
1590
|
+
[Cloudflare's Agent Skills Discovery RFC](https://github.com/cloudflare/agent-skills-discovery-rfc)
|
|
1591
|
+
v0.2.0 — which is what OpenCode's `skills.urls` consumes. One `skill-md` entry
|
|
1592
|
+
and five archives for the skills carrying `references/`, each with a sha256 of
|
|
1593
|
+
the artifact's raw bytes so a client can verify what it fetched.
|
|
1594
|
+
- The archives are built by hand as POSIX ustar with every non-content field
|
|
1595
|
+
pinned — mode 0644, uid/gid 0, mtime 0, sorted entries — because the digest is
|
|
1596
|
+
*published*. Neither the system `tar` nor a convenience library gives that by
|
|
1597
|
+
default, and an archive whose bytes move on every build publishes a digest that
|
|
1598
|
+
is wrong the moment it is written. The test asserts those header fields
|
|
1599
|
+
directly rather than only comparing two builds, since two builds agreeing is
|
|
1600
|
+
also what a tar with a coarse clock does inside one second.
|
|
1601
|
+
- Verified end to end: real `tar` extracts the archives with `SKILL.md` at the
|
|
1602
|
+
root and contents byte-identical to `skills/`, and Vite copies the
|
|
1603
|
+
dot-directory into the published output.
|
|
1604
|
+
- **This path carries skills and no MCP server**, so a client that loads them has
|
|
1605
|
+
the workflows and none of the tools they describe. `docs/install.md` says so
|
|
1606
|
+
where it offers the URL.
|
|
1607
|
+
- **Follow-up:** the first deployment served a 404, and neither the build nor
|
|
1608
|
+
Pages was at fault. `actions/upload-pages-artifact` v5 archives with
|
|
1609
|
+
`--exclude=.[^/]*` unless `include-hidden-files` is set, so it strips *every*
|
|
1610
|
+
hidden path — and a well-known URI is under a dotted directory by definition.
|
|
1611
|
+
The artifact had 465 entries and not one dot-entry, while the same build
|
|
1612
|
+
locally produced all seven files. Fixed by setting the flag, verified to add
|
|
1613
|
+
exactly `.well-known` and nothing else.
|
|
1614
|
+
|
|
1615
|
+
## Bun-only APIs cannot reach a Node bundle unnoticed — 2026-09-11
|
|
1616
|
+
|
|
1617
|
+
- Audited the shipped bundles for the defect class behind the MCP server's
|
|
1618
|
+
`import.meta.main` bug. The bundles were clean of all nine patterns checked —
|
|
1619
|
+
but the audit found the identifier still live in
|
|
1620
|
+
`src/experiments/geometry-acceptance.ts`, which **ships** (`files` carries
|
|
1621
|
+
`src/**/*.ts`). Unbundled under plain `node`, `import.meta.main` is `undefined`,
|
|
1622
|
+
so that guard was always *false* and running the script with node did nothing
|
|
1623
|
+
at all, silently. The same defect as the MCP one with its sign flipped: there,
|
|
1624
|
+
bundling made the guard always *true* and started a server nobody asked for.
|
|
1625
|
+
Both now use `isDirectEntry`, which decides from `process.argv[1]`.
|
|
1626
|
+
- A new guard asserts both halves — no Bun-only API in any committed bundle, and
|
|
1627
|
+
no `import.meta.main` deciding an entry point in shipped source. It was
|
|
1628
|
+
verified by injecting a defect into each and watching it fail, rather than
|
|
1629
|
+
trusted for passing green: the whole reason this class survived is that nothing
|
|
1630
|
+
was looking.
|
|
1631
|
+
|
|
1632
|
+
## The GPU material check runs for the first time — 2026-09-11
|
|
1633
|
+
|
|
1634
|
+
- `render-service/test/material-conformance.mjs` is the only automated evidence
|
|
1635
|
+
that the GPU path applies textures at all, and it had never passed. It replaces
|
|
1636
|
+
`globalThis.fetch` with a thrower to prove an embedded fixture never crosses a
|
|
1637
|
+
network boundary — but `blob:` is an **in-memory** object URL, and three's
|
|
1638
|
+
`GLTFLoader` mints one per embedded image that `ImageBitmapLoader` reads back
|
|
1639
|
+
through `fetch`. The guard blocked the only path a texture has into the
|
|
1640
|
+
renderer, so the file measured an untextured render and asserted against it:
|
|
1641
|
+
`lumaSpread: 0` on the albedo checker, with the real cause printed as a loader
|
|
1642
|
+
warning nobody read. `blob:` is now exempt, and the guard self-checks that an
|
|
1643
|
+
`https:` fetch still throws.
|
|
1644
|
+
- Its normal-map threshold was `>= 3` and had **never been evaluated**, because
|
|
1645
|
+
the albedo assertion above it always failed first. Recalibrated to `>= 1` from
|
|
1646
|
+
measurement. The small number is the tone curve rather than a weak response:
|
|
1647
|
+
that panel sits at mean luma ~242 of 255 under the fixture's own exposure of
|
|
1648
|
+
1.38, past the ACES shoulder. Measured 1.51 at exposure 1.38 and 2.61 at 0.9
|
|
1649
|
+
with nothing else changed — which is also the proof that the map applies. An
|
|
1650
|
+
absent normal map reads near zero, the way the albedo checker read exactly 0.
|
|
1651
|
+
- All six channels now verify: albedo, normal, shared ORM, AO, emissive, alpha.
|
|
1652
|
+
|
|
1653
|
+
## Artifact identity stops tracking the serializer's version — 2026-09-11
|
|
1654
|
+
|
|
1655
|
+
- **`asset.generator` is now a stable `"Kiln"`.** It defaulted to the serializer's
|
|
1656
|
+
own version string, so `glTF-Transform v4.4.1` sat inside every artifact's
|
|
1657
|
+
bytes and therefore inside `artifactHash`. Taking 4.5.0 moved all 83 recorded
|
|
1658
|
+
hashes and failed the gallery build — and the *entire* difference between the
|
|
1659
|
+
two GLBs was that one string. Identical BIN chunk, identical accessor min/max,
|
|
1660
|
+
identical semantic digest. With the generator pinned, **all 86 examples are
|
|
1661
|
+
byte-identical across 4.4.1 and 4.5.0**, including the ones using `palette()`,
|
|
1662
|
+
which 4.5.0 changed. A dependency's version number is provenance about the
|
|
1663
|
+
tool, not identity of the asset.
|
|
1664
|
+
- `@gltf-transform/*` moves to an exact **4.5.0**. Still exact, deliberately —
|
|
1665
|
+
the version-string cause is gone but other serialization changes are not
|
|
1666
|
+
impossible, and a serializer bump should stay a measured decision.
|
|
1667
|
+
- **A poster receipt no longer asserts `artifactHash`.** It asserts `sourceHash`
|
|
1668
|
+
and `imageHash` — this image was rendered from this source — which is what it
|
|
1669
|
+
could always honestly claim. Asserting the container's bytes claimed something
|
|
1670
|
+
glTF never promised: that rebuilding a source on another platform reproduces
|
|
1671
|
+
it byte for byte. The hash stays in the record as provenance, naming the bytes
|
|
1672
|
+
the poster was rendered from on the machine that recorded it, and the prose in
|
|
1673
|
+
all 83 records no longer calls the poster a render of "the exact downloadable
|
|
1674
|
+
GLB".
|
|
1675
|
+
- Within-run integrity checks are untouched and still hash bytes: the gallery
|
|
1676
|
+
index against the files built beside it, the build receipt against the index,
|
|
1677
|
+
and both demo receipts against their own run's GLBs.
|
|
1678
|
+
- **The gallery now builds on Linux.** `bun run site:assets` followed by
|
|
1679
|
+
`site/scripts/verify-assets.mjs` completes — 80 source/GLB pairs, posters, both
|
|
1680
|
+
edit-demo revisions and the geometry example. Before this it failed on the
|
|
1681
|
+
first example.
|
|
1682
|
+
- `pages.yml` now runs `site/scripts`'s tests explicitly. **Correction:** this
|
|
1683
|
+
entry first said those tests had never run in any workflow. They had. `bun run
|
|
1684
|
+
test` is `bun test src scripts`, bun treats those as substring filters on
|
|
1685
|
+
paths, and `site/scripts` matches `scripts` — so both files were already in the
|
|
1686
|
+
suite CI runs. The step stays for a smaller reason: that coverage is
|
|
1687
|
+
incidental, and spelling the script `bun test ./src ./scripts` would drop it
|
|
1688
|
+
silently.
|
|
1689
|
+
- **The gallery no longer builds on Windows.** `pages.yml` is `ubuntu-latest`,
|
|
1690
|
+
which closes Phase 6.
|
|
1691
|
+
- New `scripts/glb-chunk-hashes.mjs` splits a GLB by chunk, and it answered the
|
|
1692
|
+
question Phase 6 opened with. Measured on 8 examples across both platforms at
|
|
1693
|
+
one commit: the JSON chunk diverges in **all 8**, the BIN chunk in **2 of 8**,
|
|
1694
|
+
and totals move by 4, 8 and 264 bytes — digit counts changing, which a
|
|
1695
|
+
formatting difference cannot do, because ECMAScript specifies number-to-string
|
|
1696
|
+
exactly. So the divergence is the float values themselves, most likely the
|
|
1697
|
+
transcendentals, which IEEE-754 does not bit-specify. That means no canonical
|
|
1698
|
+
serialization could ever have fixed it, and narrowing the receipt was the only
|
|
1699
|
+
option that works.
|
|
1700
|
+
|
|
1701
|
+
## The renderer starts itself, and now ships — 2026-09-11
|
|
1702
|
+
|
|
1703
|
+
- The MCP server **starts the GPU render service on demand**. Installing it
|
|
1704
|
+
(`cd render-service && npm install`) is the whole setup: there is no longer a
|
|
1705
|
+
second process to start first, and nothing to restart to pick one up. The
|
|
1706
|
+
first view that needs PBR shading starts the renderer, the rest of the session
|
|
1707
|
+
reuses it, and it stops when the server does. Measured end to end on the
|
|
1708
|
+
shipped bundle with nothing listening: the first `kiln_render` came back
|
|
1709
|
+
material-faithful from the GPU in 5.4 s, the second in 1.7 s.
|
|
1710
|
+
- A service already listening is **joined, not replaced**, and a session that
|
|
1711
|
+
merely found one does not stop it on the way out -- so one GPU shared by a
|
|
1712
|
+
batch of dispatched agents keeps working, and the agent that finishes first
|
|
1713
|
+
cannot pull the renderer out from under the others.
|
|
1714
|
+
- A machine that did not install the renderer is **unchanged**, deliberately
|
|
1715
|
+
and at the level of the attached port rather than the rendered result: the
|
|
1716
|
+
absence of a render port is what makes an ordinary CPU view read as ordinary
|
|
1717
|
+
instead of as a degrade.
|
|
1718
|
+
- `KILN_RENDER_PORT_URL` and `--render-port` short-circuit all of it, so a
|
|
1719
|
+
hosted or remote GPU is still exactly one flag. `KILN_RENDER_SERVICE_PORT`
|
|
1720
|
+
moves the local one off 8000.
|
|
1721
|
+
- The CLI is deliberately not on this path: a one-shot `kiln render` should not
|
|
1722
|
+
pay a GPU process's startup to draw one sheet.
|
|
1723
|
+
- **`render-service/` now ships in the package.** The MCP server told every model
|
|
1724
|
+
that a GPU renderer "ships as render-service/ in this installation"; that was
|
|
1725
|
+
false for anyone installing from npm, because the directory was in no `files`
|
|
1726
|
+
entry. Its source travels with the package now (104 KB) while its ~94 MB of
|
|
1727
|
+
native dependencies stay an explicit opt-in install.
|
|
1728
|
+
- `webgpu` 0.4.0 -> 0.6.0, smoked on hardware: 36/36 service unit tests, display
|
|
1729
|
+
conformance passed, end-to-end smoke all pass.
|
|
1730
|
+
- A service started **for** you binds loopback; one you start yourself still binds
|
|
1731
|
+
every interface, which is what a container deployment needs. `HOST` is now
|
|
1732
|
+
honoured either way.
|
|
1733
|
+
|
|
1734
|
+
## Review surfaces say what they mean — 2026-09-11
|
|
1735
|
+
|
|
1736
|
+
- `viewFidelity.exactArtifact` was a hard-coded `false` literal at every
|
|
1737
|
+
`kiln_render` site, never computed. A flag that is always false carries no
|
|
1738
|
+
information, and this one invited the opposite of the truth: a model could
|
|
1739
|
+
read it as "these bytes differ from what I would export" when the bytes are
|
|
1740
|
+
frequently identical. The value is still false -- this surface only ever
|
|
1741
|
+
renders an in-loop build -- but it now carries the reason code
|
|
1742
|
+
`IN_LOOP_BUILD_NOT_PERSISTED`, so the false value is readable rather than
|
|
1743
|
+
ominous.
|
|
1744
|
+
- `kiln_screenshot_animation` was reported to rotate a whole asset where the
|
|
1745
|
+
clip drives one joint. **It does not.** Measured on world matrices rather than
|
|
1746
|
+
pixels: a one-channel clip moves the joint's subtree through a clean
|
|
1747
|
+
180-degree yaw while the un-animated sibling holds the origin at every phase.
|
|
1748
|
+
An image cannot tell a turret sweeping from a scene spinning, which is why the
|
|
1749
|
+
report was plausible; a regression test now stands where the doubt was.
|
|
1750
|
+
- `arrayLinear` and `arrayRadial` say outright that `count` is the total
|
|
1751
|
+
including the source, which survives as copy 0 -- so `count: 8` gives eight
|
|
1752
|
+
bolts, not nine. The program contract states that
|
|
1753
|
+
`kiln_screenshot_animation` requires `clip` by name, that `frameTimes` is
|
|
1754
|
+
phases in 0..1 rather than seconds, and that a clip that renders frozen means
|
|
1755
|
+
a joint-name mismatch surfaced in `unresolvedTracks`.
|
|
1756
|
+
|
|
1757
|
+
## Dependency refresh — 2026-09-11
|
|
1758
|
+
|
|
1759
|
+
- Patch and minor bumps with no API surface change: `@types/three` 0.185.4,
|
|
1760
|
+
`acorn` 8.18.0, `manifold-3d` 3.5.3, `sharp` 0.35.4, `zod` 4.6.2,
|
|
1761
|
+
`@anthropic-ai/sdk` 0.125.0, `@biomejs/biome` 2.5.13, `@google/genai` 2.22.0,
|
|
1762
|
+
`@strands-agents/sdk` 1.17.0. `biome.json` follows Biome's own version, which
|
|
1763
|
+
the linter checks and which is what actually failed the gate; one test file
|
|
1764
|
+
picks up the new formatter's line fitting.
|
|
1765
|
+
- **`@gltf-transform/*` is now pinned to exactly 4.4.1**, joining `three` and
|
|
1766
|
+
`gltf-validator`. 4.5.0 changes the bytes of every exported GLB: all 83
|
|
1767
|
+
recorded `artifactHash` values move, and the gallery build fails on a stale
|
|
1768
|
+
poster. A caret range on the library that serializes the artifact means the
|
|
1769
|
+
artifact's identity can change on an unrelated install, which is not a
|
|
1770
|
+
property this project can have. Taking 4.5.0 is a deliberate act with receipts
|
|
1771
|
+
re-recorded in the same pass, not a refresh.
|
|
1772
|
+
- `three` stays at 0.185.1. `@types/three` has no 0.186.x published, and r186
|
|
1773
|
+
renames `Source` to `TextureSource` and makes
|
|
1774
|
+
`BufferGeometryUtils.toTrianglesDrawMode()` mutate in place rather than clone.
|
|
1775
|
+
Taking the runtime without the types would be a net loss.
|
|
1776
|
+
|
|
1777
|
+
## Toolchain moved to Bun 1.4.2, and the MCP bundle stopped starting itself — 2026-09-11
|
|
1778
|
+
|
|
1779
|
+
- Development toolchain pins move to Bun 1.4.2, Node 22.23.2 and npm 12.0.2.
|
|
1780
|
+
Bun 1.4 also fixes the early-exit behaviour above at its source: the pre-fix
|
|
1781
|
+
CLI, which produced empty output in 6 of 8 concurrent runs on 1.3.14, produced
|
|
1782
|
+
full output in 16 of 16 on 1.4.2. The `withProcessAlive` guard stays -- it
|
|
1783
|
+
holds for anyone still on 1.3.x, and nothing in the runtime contract promises
|
|
1784
|
+
otherwise. The offline suite runs about 18% faster.
|
|
1785
|
+
- **`dist/mcp-server.mjs` started a stdio server when merely imported, and had
|
|
1786
|
+
done so for as long as the bundle has existed.** The source guarded its entry
|
|
1787
|
+
block with `import.meta.main`, a Bun property that no Bun release lowers
|
|
1788
|
+
correctly for a `--target=node` bundle. Every lowering emits
|
|
1789
|
+
`__require.main == __require.module`; under Node ESM both sides are
|
|
1790
|
+
`undefined`, so the guard was always true. Bun 1.4 then stopped emitting the
|
|
1791
|
+
`__require` helper that line still references, which turned the same
|
|
1792
|
+
expression into a `ReferenceError` before the server could speak -- loud where
|
|
1793
|
+
it had been silent, and how this was finally caught. Both entries now decide
|
|
1794
|
+
from `process.argv[1]` through a shared `isDirectEntry`, which needs no
|
|
1795
|
+
lowering and means the same thing on both runtimes.
|
|
1796
|
+
|
|
1797
|
+
## `kiln` commands no longer exit 0 in silence under Bun — 2026-09-11
|
|
1798
|
+
|
|
1799
|
+
- Under Bun, a CLI command could exit 0 having written nothing at all: no output,
|
|
1800
|
+
no error, no rejection. `kiln save` did it reproducibly under load. The command
|
|
1801
|
+
was not failing, it was still running -- Bun does not register the in-flight work
|
|
1802
|
+
as an active resource, so the event loop went idle and the process exited before
|
|
1803
|
+
`main()` settled. Every entry point was exposed, the generated workspace
|
|
1804
|
+
`kiln.mjs` launcher included, because all of them await `main()` and then set
|
|
1805
|
+
`process.exitCode`. `main` now holds the process open for its own duration.
|
|
1806
|
+
Node was unaffected in practice, but the guard is runtime-agnostic.
|
|
1807
|
+
- Every CLI destination now creates the directories leading to it. `--out` and
|
|
1808
|
+
`--views` failed with a bare `ENOENT` on a missing parent, and failed *after*
|
|
1809
|
+
the build had run and printed a `programRef` -- a successful render followed by
|
|
1810
|
+
an error naming a path but not the directory as the thing to fix. Covers
|
|
1811
|
+
`render --out`, `render --views`, `generate`, `source <ref> --out` and
|
|
1812
|
+
`export --out`.
|
|
1813
|
+
|
|
1814
|
+
## Usable from a bare clone by any harness; isolate honored on GPU — 2026-09-10
|
|
1815
|
+
|
|
1816
|
+
- A bare clone is now usable by claude, codex, opencode, hermes and agy. The root
|
|
1817
|
+
`.mcp.json` pointed at `${PLUGIN_ROOT}`, which only Antigravity defines, so the
|
|
1818
|
+
server failed to start with MODULE_NOT_FOUND in every other host; it now uses
|
|
1819
|
+
`${CLAUDE_PROJECT_DIR:-.}`, which resolves whether or not the variable is set.
|
|
1820
|
+
`CLAUDE.md` imports `AGENTS.md` rather than duplicating it, and the
|
|
1821
|
+
`kiln-setup-workspace` skill is registered at `.claude/skills/` and
|
|
1822
|
+
`.agents/skills/` so a clone opened for an asset task is told to build a
|
|
1823
|
+
workspace instead of authoring in the engine checkout.
|
|
1824
|
+
- `visibility: 'isolate'` and the legacy `isolate: true` were silently ignored
|
|
1825
|
+
whenever a GPU service was attached. Both hide geometry by clearing
|
|
1826
|
+
`mesh.visible`; the CPU rasterizer culls on that flag, but glTF carries no
|
|
1827
|
+
per-mesh visibility, so the derivative GLB shipped the hidden meshes and the
|
|
1828
|
+
service drew them. `kiln_inspect` was reporting "nothing in this image occludes
|
|
1829
|
+
it" about images where everything still did. The derivative serialization now
|
|
1830
|
+
prunes hidden meshes from a copy, leaving the caller's scene untouched. The
|
|
1831
|
+
only previous test framed a single-mesh scene, where isolation cannot change
|
|
1832
|
+
the image.
|
|
1833
|
+
- The generated workspace guide is organised around the authoring loop rather
|
|
1834
|
+
than a flat tool list, and presents the MCP server and `node kiln.mjs` as equal
|
|
1835
|
+
surfaces that may be mixed, naming the two things that actually differ: where
|
|
1836
|
+
the rendered image lands, and that a CPU view is not material evidence. It also
|
|
1837
|
+
names the GPU render service, resolving the engine path through
|
|
1838
|
+
`.kiln/workspace.json` so `--repair` keeps it accurate, and asks the session to
|
|
1839
|
+
report skills and MCP servers it inherited from user-level configuration.
|
|
1840
|
+
- `START.md` printed a literal `/current/kiln/` in its repair command; it now
|
|
1841
|
+
prints the recorded installation path plus how to recover if that moved.
|
|
1842
|
+
|
|
1843
|
+
## Smaller clone; gallery images served from R2 — 2026-09-10
|
|
1844
|
+
|
|
1845
|
+
- Gallery renders and launch video are no longer carried in git history. A clone
|
|
1846
|
+
costs 52 MB and 8 seconds rather than 440 MB and 79 seconds, 48 MB with
|
|
1847
|
+
`--filter=blob:none`, and a plugin install no longer pays for 539 MB of
|
|
1848
|
+
repository content twice. Packed history went from 226.06 MiB to 17.41 MiB.
|
|
1849
|
+
- The 88 gallery images moved to Cloudflare R2 byte for byte and are served from
|
|
1850
|
+
`assets.kilnstudio.tools`. Nothing was re-encoded: all 83 poster receipts still
|
|
1851
|
+
verify against the stored objects, and `scripts/verify-posters.mjs` checks that
|
|
1852
|
+
on every gallery build.
|
|
1853
|
+
- **This rewrote history.** All 177 commits survived and the tree is unchanged
|
|
1854
|
+
apart from the removed images and video, but every commit hash changed. Clones
|
|
1855
|
+
predating this cannot fast-forward; see the note in `README.md`. Links pinned to
|
|
1856
|
+
an old commit SHA will stop resolving; links through `main` are unaffected.
|
|
1857
|
+
- The launch video was never what the README served -- that comes from GitHub's
|
|
1858
|
+
asset CDN -- so the README is unaffected. `assets/gallery/` deliberately stays
|
|
1859
|
+
in the repository, so the README grid needs no network.
|
|
1860
|
+
- Re-encoding the posters to shrink them was considered and rejected: image tokens
|
|
1861
|
+
scale with pixel dimensions, not file size, so it would have saved no agent
|
|
1862
|
+
context while voiding all 83 receipts.
|
|
1863
|
+
|
|
1864
|
+
Full record, including everything rejected and why, in
|
|
1865
|
+
[docs/plans/repo-size-and-r2-migration-2026-09-10.md](docs/plans/repo-size-and-r2-migration-2026-09-10.md).
|
|
1866
|
+
|
|
1867
|
+
## Collections and chat viewing — 2026-09-06
|
|
1868
|
+
|
|
1869
|
+
- Save assets into project or personal collections with immutable revisions,
|
|
1870
|
+
hashed provenance, original source, and portable editable ZIP bundles.
|
|
1871
|
+
- Browse collections and imported GLBs in a local viewer with animation controls,
|
|
1872
|
+
revision inspection, and GLB/source/bundle downloads.
|
|
1873
|
+
- Present saved assets in supporting MCP App clients with `kiln_present`.
|
|
1874
|
+
ChatGPT viewing was verified; native GLB/ZIP attachment delivery remains
|
|
1875
|
+
unverified. Host-provided download links are supported.
|
|
1876
|
+
- Package complete skills independently or bind them to a ChatGPT connector.
|
|
1877
|
+
- Add a canonical-only sitemap and crawler discovery file to the project site.
|
|
1878
|
+
|
|
1879
|
+
See [dogfood results and remaining work](docs/collections-dogfood.md) and
|
|
1880
|
+
[indexing diagnostics](docs/site-indexing.md). Package version remains 0.6.0;
|
|
1881
|
+
this change does not publish a new npm package or promote dogfood assets.
|
|
1882
|
+
|
|
1883
|
+
## Public OSS snapshot — 2026-09-05
|
|
1884
|
+
|
|
1885
|
+
- Short, immutable source references work across rendering, source reads, edits,
|
|
1886
|
+
CLI exports, and MCP restarts. Full hashes remain compatible.
|
|
1887
|
+
- Project-local setup and skills support authoring, inspection, and refinement
|
|
1888
|
+
through the CLI, MCP server, and TypeScript tools.
|
|
1889
|
+
- Geometry modifiers and configurable asset/part cameras extend the authoring
|
|
1890
|
+
and review workflow.
|
|
1891
|
+
- The redesigned site includes 62 selected assets with source downloads, GLB
|
|
1892
|
+
viewers, attribution, and recorded revision histories where available.
|
|
1893
|
+
- Mechanical Peacock and Deco Radio include documented maintainer repairs.
|
|
1894
|
+
Brass Tellurion and Victorian Greenhouse remain archived outside the gallery.
|
|
1895
|
+
- Package checks cover Windows, Linux, and hosted Apple Silicon/Intel Macs.
|
|
1896
|
+
|
|
1897
|
+
The snapshot retains package version 0.6.0. Earlier development notes follow;
|
|
1898
|
+
their asset counts and workflow descriptions describe those earlier revisions.
|
|
1899
|
+
|
|
1900
|
+
## [Unreleased]
|
|
1901
|
+
|
|
1902
|
+
### Changed
|
|
1903
|
+
- **`site/` is a project site now, not a gallery.** The front page was a wall of
|
|
1904
|
+
specimens with a tally of triangles above it, which answered a question nobody
|
|
1905
|
+
arriving from a link was asking. It now opens on what Kiln is, the offline command
|
|
1906
|
+
that proves the engine works with no model and no key, the exact configuration for
|
|
1907
|
+
each of the five harnesses with the gotcha that cost time in each one, and a map of
|
|
1908
|
+
where to look in the repository; the specimens moved behind `#/gallery` and are
|
|
1909
|
+
reached from a strip of eight. The aggregate counts are gone -- a number is a claim
|
|
1910
|
+
about the library, and the library is the thing on the other page. Per-card model
|
|
1911
|
+
attribution stays, because that is not a statistic. `REPO` and `asset()` moved out of
|
|
1912
|
+
`App.tsx` into a leaf module: once `App` imported a page that read one at module
|
|
1913
|
+
scope the cycle turned into a blank screen at first paint, and a module that imports
|
|
1914
|
+
nothing cannot be in a cycle.
|
|
1915
|
+
|
|
1916
|
+
### Fixed
|
|
1917
|
+
- **The carousel and orrery GIFs no longer show something the programs beside them
|
|
1918
|
+
stopped producing.** Both were flagged in review as showing an earlier revision, and
|
|
1919
|
+
both were regenerated on the GPU port from the current source. Nothing in the repo
|
|
1920
|
+
ties a GIF to the revision it was rendered from, so the staleness was caught by
|
|
1921
|
+
somebody remembering rather than by a gate -- the stills have the same exposure.
|
|
1922
|
+
A frame overlay confirms the camera is fixed across both loops and only the authored
|
|
1923
|
+
motion moves.
|
|
1924
|
+
|
|
1925
|
+
### Added
|
|
1926
|
+
- **A specimen gallery in `site/`, built by running the programs rather than by
|
|
1927
|
+
committing meshes.** The README's stills are a weak claim about geometry -- a lit
|
|
1928
|
+
render hides topology, and a reader has no way to tell a dense mesh from a clean one.
|
|
1929
|
+
The gallery loads all fifty as real GLBs with orbit controls, a wireframe toggle and
|
|
1930
|
+
the triangle count, draw calls, material count and bounds off the engine's own
|
|
1931
|
+
integration manifest. Nothing in it is checked in: `site/scripts/build-assets.mjs`
|
|
1932
|
+
runs each `examples/*.kiln.js` through the same evaluator the test suite uses and
|
|
1933
|
+
keeps what comes back, so a program and the mesh on the page cannot drift, and a
|
|
1934
|
+
program that stops building fails the deploy. Attribution on each card comes from the
|
|
1935
|
+
program's own header through `scripts/authorship.ts` -- extracted from the authorship
|
|
1936
|
+
test so that the README and the gallery read the headers with one parser instead of
|
|
1937
|
+
two that will eventually disagree. React and three live in `site/` and nowhere else;
|
|
1938
|
+
the engine still has no browser dependency. `.github/workflows/pages.yml` deploys it.
|
|
1939
|
+
- **A fifth skill, `kiln-batch-dispatch`, for the person pointing agents at the problem
|
|
1940
|
+
rather than the agent building the asset.** The other four are read by whoever is
|
|
1941
|
+
holding the geometry; this one covers wiring a harness up, proving the tools are
|
|
1942
|
+
actually reachable before trusting a single result, and running the clean-room
|
|
1943
|
+
dispatcher across models and subjects until you have a library. It exists because
|
|
1944
|
+
the two halves fail as one: a batch launched on unproven wiring produces a pile of
|
|
1945
|
+
empty sandboxes, and no way to tell whether the models were weak or the tools were
|
|
1946
|
+
never there. It also writes down the two limits that cost the most time here -- a
|
|
1947
|
+
harness's default output cap silently truncating a model mid-file, and a run cut off
|
|
1948
|
+
at its deadline still being a success if a usable program is on disk.
|
|
1949
|
+
- **`--category` on the dispatcher, with six experimental values and one honest
|
|
1950
|
+
default.** Every asset ever dispatched from this repository came back
|
|
1951
|
+
`category: 'prop'`, because the brief said so in a string literal. The problem was
|
|
1952
|
+
never that they were props -- most of them are, correctly, and almost anything can be
|
|
1953
|
+
built as one -- but that the field carried no information, so a library could not be
|
|
1954
|
+
sorted by it and the engine's per-category guidance was unreachable. The flag takes
|
|
1955
|
+
any of the seven contract values and rejects anything else in the first second rather
|
|
1956
|
+
than filing an asset under nothing. `prop` stays the default and its brief is
|
|
1957
|
+
deliberately empty, which makes it the least constrained thing the dispatcher can
|
|
1958
|
+
send. The other six append a short note on what tends to go wrong for that kind of
|
|
1959
|
+
subject, and they are a bet rather than a taxonomy: worth reaching for when the
|
|
1960
|
+
subject really is a building or a plant, worth dropping first when a run comes back
|
|
1961
|
+
worse than the same brief as a prop. `src/__tests__/dispatch-categories.test.ts` fails
|
|
1962
|
+
if the list the script carries ever drifts from `ASSET_CATEGORIES`.
|
|
1963
|
+
- **Hermes as a fifth harness, which is the first real evidence that any of this is
|
|
1964
|
+
portable.** The other four are JavaScript CLIs that broadly agree on what a plugin
|
|
1965
|
+
is; Hermes is a Python agent with its own YAML config, its own skill store and its
|
|
1966
|
+
own provider routing, sharing no code and no convention with them. It takes the
|
|
1967
|
+
same `dist/mcp-server.mjs` and the same `skills/` directory unchanged: `hermes mcp
|
|
1968
|
+
add` connects on the spot and enumerates all seven tools, and
|
|
1969
|
+
`hermes config set skills.external_dirs` registers every shipped skill as `local`. It
|
|
1970
|
+
does not read `.claude/skills` out of the working directory the way the others do,
|
|
1971
|
+
and that config key is the whole difference. Smoke-tested green at 97s on a free
|
|
1972
|
+
model. `-z` is the headless mode the dispatcher drives, and since it has no
|
|
1973
|
+
working-directory flag the sandbox is simply the CWD it is spawned in -- which is
|
|
1974
|
+
also where it reads `AGENTS.md`, so the clean room holds without extra work.
|
|
1975
|
+
- **`bun run smoke:harness`, which proves a harness can reach the tools.** Every
|
|
1976
|
+
wiring failure in this project has been silent: `agy plugin validate` reports the
|
|
1977
|
+
MCP server as processed while `agy mcp list` shows none, and a harness that can
|
|
1978
|
+
see the tools but will not grant them answers exactly like one that never had
|
|
1979
|
+
them -- which is also what a model too weak for the job looks like. Three
|
|
1980
|
+
indistinguishable failures with one symptom is a thing worth being able to test,
|
|
1981
|
+
so this sends a short brief into a throwaway directory -- call
|
|
1982
|
+
`kiln_list_primitives`, write a four-line program, validate it -- and then builds
|
|
1983
|
+
what came back with the engine, because the child's own report of success is the
|
|
1984
|
+
only evidence that proves nothing. Measured on one machine: Claude Code 13s,
|
|
1985
|
+
OpenCode 37s, Antigravity 105s, each green. Codex reached the model and stopped
|
|
1986
|
+
at its account's own usage limit, which is the diagnosis the script exists to
|
|
1987
|
+
make -- the wiring is fine and the provider is out. Codex has since been smoked
|
|
1988
|
+
green as well, at 37s, once the flag below let it call a tool at all.
|
|
1989
|
+
- **A fourth vendor in the gallery, and a wider spread of subject.** This step took
|
|
1990
|
+
the heroes to twenty-seven, and the additions were chosen for the range they prove
|
|
1991
|
+
rather than for how they look: a supercarrier, a phased-array air-defence radar,
|
|
1992
|
+
a fighter with a lofted aerofoil and a geostationary comms satellite, which are
|
|
1993
|
+
the subjects where a program has to compute its shape rather than place it, and a
|
|
1994
|
+
Dutch tower windmill written by DeepSeek V4 Flash -- the first asset here from a
|
|
1995
|
+
fourth vendor's model, dispatched clean-room through OpenCode like the Muse Spark
|
|
1996
|
+
ones. The anglerfish was rebuilt: the first was a smooth dark cone with a jaw
|
|
1997
|
+
drawn on it, and organic form is the case this tool is worst at, so it is the one
|
|
1998
|
+
worth showing honestly. Eleven of those twenty-seven were not written by Claude.
|
|
1999
|
+
- **Tangents for non-indexed geometry.** `computeTangentBasis` required an index
|
|
2000
|
+
buffer and warned, per mesh, when there was not one -- so a normal map on any
|
|
2001
|
+
flat-shaded part, anything merged from several geometries, and anything through
|
|
2002
|
+
`.toNonIndexed()` shipped with no TANGENT attribute and a note saying each runtime
|
|
2003
|
+
would guess its own. That is most of what a hand-built asset is made of. A
|
|
2004
|
+
triangle soup is an index buffer that reads 0, 1, 2, ..., so the same accumulation
|
|
2005
|
+
is exactly right for it and every vertex comes out holding its own face's tangent;
|
|
2006
|
+
a test unwelds a box and checks the soup and the indexed copy agree per vertex.
|
|
2007
|
+
`examples/anglerfish.kiln.js` had twelve of those warnings and now has none.
|
|
2008
|
+
- **A measured ceiling on the always-on context cost.** `src/__tests__/mcp-payload.test.ts`
|
|
2009
|
+
now derives the JSON Schema for all seven tools and sums the front matter of every
|
|
2010
|
+
shipped skill, holds each under a budget, and requires the README to quote the real
|
|
2011
|
+
figures. The README argued the surface was small with numbers nothing was checking.
|
|
2012
|
+
- **`kiln_edit`, the refine verb, and the `kiln-refine-asset` skill that drives it.**
|
|
2013
|
+
Every MCP tool took a whole program and rendered it, so changing one line of a
|
|
2014
|
+
finished asset meant re-emitting the entire file and trusting that the other two
|
|
2015
|
+
hundred lines came back unchanged. `kiln_edit` takes exact-string replacements
|
|
2016
|
+
instead: they apply in order, a match that is not unique is refused rather than
|
|
2017
|
+
guessed at, and if any edit fails **nothing** is applied -- so a bad edit costs a
|
|
2018
|
+
retry rather than a program in a state the model never asked for. It returns the
|
|
2019
|
+
patched source, a unified diff, and the six-view sheet together, because the loop
|
|
2020
|
+
is edit-then-look. It is deliberately stateless: the in-process agent keeps a
|
|
2021
|
+
working buffer across turns, but over MCP the host holds the program text, and a
|
|
2022
|
+
second copy inside the server would have been a desync the model cannot see. The
|
|
2023
|
+
buffer itself moved to `src/edit-buffer.ts` so both transports share one
|
|
2024
|
+
implementation -- importing it from `agent/tools.ts` would have pulled
|
|
2025
|
+
`@strands-agents/sdk` into `kiln/tools` and into the MCP bundle, which is the one
|
|
2026
|
+
edge that subpath is documented not to have. Like the unified `kiln_render`, the
|
|
2027
|
+
def sits outside `createKilnToolRegistry`, whose four tools are a frozen bench
|
|
2028
|
+
baseline.
|
|
2029
|
+
- **The scanned texture library doubled, from eight CC0 families to sixteen.** The
|
|
2030
|
+
first eight were all rough exterior surfaces, which left three material recipes --
|
|
2031
|
+
`skin`, `leaf`, and `rubber` -- with nothing photographic to bind at all, and made
|
|
2032
|
+
rust the only metal in the package. Added: brown leather, forest leaf litter,
|
|
2033
|
+
rubber tiles, riveted steel plate, clay roof tiles, cobblestone paving, finished
|
|
2034
|
+
oak veneer, and polished marble. 48 maps, 747,977 embedded bytes, still inside the
|
|
2035
|
+
1 MiB package budget the test enforces.
|
|
2036
|
+
- **OpenCode support, and clean-room dispatch.** `scripts/dispatch-asset.mjs` gained an
|
|
2037
|
+
`opencode` harness, reaching a dozen vendors' models behind `provider/model` ids.
|
|
2038
|
+
More importantly, every dispatch now runs in its own directory containing only the
|
|
2039
|
+
brief and the Kiln skills. Dispatches previously ran with the harness pointed
|
|
2040
|
+
at this repository, where a child agent could read thirteen finished example
|
|
2041
|
+
programs -- which quietly invalidated the claim those runs were evidence for. The
|
|
2042
|
+
write grant is scoped to the sandbox, and the authoring model is stamped into the
|
|
2043
|
+
program it wrote. `examples/gramophone.kiln.js` is the first asset in the gallery
|
|
2044
|
+
actually built that way -- authored through OpenCode by
|
|
2045
|
+
`muse-spark-1.3-contributor`, a third vendor's model, in a directory holding
|
|
2046
|
+
nothing but the brief and the skills. Every other example predates the sandbox and
|
|
2047
|
+
is attributed without the clean-room claim.
|
|
2048
|
+
- **Animated GIFs of the animated examples, via `scripts/anim-gifs.ts`.** The
|
|
2049
|
+
render port fits its camera to the bounding box it is handed, which is right for
|
|
2050
|
+
a still and wrong for a sequence -- a robot arm's posed extent varies 63% across
|
|
2051
|
+
its cycle, so the asset would appear to breathe as the camera refit itself each
|
|
2052
|
+
frame. Because the projection is orthographic and the port's fit is exact, each
|
|
2053
|
+
frame is put back onto one shared camera afterwards by a scale and a translation
|
|
2054
|
+
that are both computable, so the result is a fixed camera rather than an
|
|
2055
|
+
approximation of one.
|
|
2056
|
+
- **`scripts/check-vision.mjs`, a preflight that refuses to dispatch a blind model.**
|
|
2057
|
+
Kiln's loop is the model looking at its own render, so image input is the one
|
|
2058
|
+
capability that is not optional -- and a text-only model does not fail, it just
|
|
2059
|
+
builds worse assets from the documentation alone. A nine-model batch here was
|
|
2060
|
+
found to contain four text-only models, picked by name on the assumption that a
|
|
2061
|
+
current flagship accepts images. Vision also varies between a vendor's own
|
|
2062
|
+
variants: `glm-5.3-flash` sees images and `glm-5.3` does not. The check reads
|
|
2063
|
+
OpenCode's cached model metadata, costs about two seconds for any number of
|
|
2064
|
+
models, and exits non-zero naming the offenders.
|
|
2065
|
+
- **Browser-safe GLB integration manifest.** Every `renderGLB` / `renderSceneToGLB`
|
|
2066
|
+
result now carries `kiln.integration-manifest.v1`: artifact SHA-256, metre/+Y-up
|
|
2067
|
+
coordinate semantics, world bounds, ground offset, role, render metrics, and
|
|
2068
|
+
structural-validator counts. `inspectGlbIntegration(bytes)` derives the same
|
|
2069
|
+
contract from finished bytes without executing model-authored source.
|
|
2070
|
+
- **Four assets from a sixth model, through a sixth harness.** GPT-6 Astra wrote an
|
|
2071
|
+
orbital station, a rigid airship at its mooring mast, a blast furnace and a Gothic
|
|
2072
|
+
clock tower, dispatched through Codex into the usual clean room. They are the first
|
|
2073
|
+
batch in this repository where every program cleared the zero-structural-warning bar
|
|
2074
|
+
the shipped examples are held to on the first pass, with no hand repair and no
|
|
2075
|
+
promotion-time fix, at 10,212 / 11,764 / 11,964 / 11,664 triangles. The gallery is
|
|
2076
|
+
now fifty programs, thirty-five of them written by something other than Claude.
|
|
2077
|
+
|
|
2078
|
+
### Fixed
|
|
2079
|
+
- **The Codex harness could not call a single tool, and said so only in the child's
|
|
2080
|
+
transcript.** `codex exec` pins its approval policy to `never`, and a `never` policy
|
|
2081
|
+
does not queue an MCP call for later approval, it refuses it outright -- so four
|
|
2082
|
+
dispatches came back inside a minute each having written nothing but a note that
|
|
2083
|
+
`kiln_list_primitives` was blocked. The dispatcher passed `--sandbox
|
|
2084
|
+
workspace-write`, which grants the filesystem and says nothing about tools;
|
|
2085
|
+
`--approve-for-me` is the flag that does both, selecting the same sandbox and moving
|
|
2086
|
+
approval to automatic review, and the two are mutually exclusive on the command line
|
|
2087
|
+
for exactly that reason. Worth noting alongside it: `codex plugin add` installs this
|
|
2088
|
+
repository's manifest happily and registers neither its MCP servers nor its skills,
|
|
2089
|
+
so the TOML server block is still required -- the same trap `agy` sets, failing the
|
|
2090
|
+
same silent way. Both are now documented per-harness in `docs/install.md`.
|
|
2091
|
+
- **`cylinderUnwrap` now unwraps cylindrically, which it has always claimed to do.**
|
|
2092
|
+
It and `boxUnwrap` were the same function: both preserved existing UVs and both fell
|
|
2093
|
+
back to the same flat projection, so on the one case the file's own header describes
|
|
2094
|
+
-- a curved surface carrying a directional texture -- brick came out as horizontal
|
|
2095
|
+
smears. Built-in `cylinderGeo` never hit it because Three.js ships UVs with it;
|
|
2096
|
+
anything swept or extruded did, and a texture-backed material on unwrapped geometry
|
|
2097
|
+
is a QA blocker rather than a silent miss. It now runs u around the Y axis and v up
|
|
2098
|
+
the height, normalized across the geometry's own angular span so a 22 degree curb
|
|
2099
|
+
stone gets the whole texture rather than six percent of its width, with caps
|
|
2100
|
+
projected flat so they do not sample a single row of texels.
|
|
2101
|
+
- **The well, which was a ring of boxes pretending to be masonry.** A box has parallel
|
|
2102
|
+
sides, so on a circle its neighbours meet it at an angle and the joint opens into a V
|
|
2103
|
+
that widens toward the outside face -- 40 mm of it at the outer radius, sixteen times
|
|
2104
|
+
around, which read as a cog wheel with a dark slot at every tooth. The curb is now cut
|
|
2105
|
+
the way a mason would cut it: wedge stones whose side faces lie on radial planes,
|
|
2106
|
+
inner and outer faces following the curve, in two courses offset by half a step so no
|
|
2107
|
+
joint runs the full height. The shaft is lined with an extruded ring rather than a
|
|
2108
|
+
solid cylinder, since the hole is the point of a well, and there is water at the
|
|
2109
|
+
bottom of it. The roof posts are bedded rather than balanced: a square post stopped on
|
|
2110
|
+
a round wall always reads as overhanging it, because from any angle where the wall
|
|
2111
|
+
curves away it does, so each post now runs past both courses to the plinth and the
|
|
2112
|
+
three stones on its line are cut around it with `boolDiff`. Only those stones lose
|
|
2113
|
+
their instancing -- an angular overlap test picks them out, one per post in the
|
|
2114
|
+
un-skewed course and two in the skewed one where the post straddles a joint.
|
|
2115
|
+
- **The pinball machine's backbox, which stood on nothing.** It was built entirely
|
|
2116
|
+
behind the cabinet's rear face, cantilevered off a 30 mm wall. Sliding it forward onto
|
|
2117
|
+
the cabinet only traded one fault for another: the playfield runs the cabinet's full
|
|
2118
|
+
length, so everything the head gained in support it took out of the glass, and at
|
|
2119
|
+
380 mm deep it buried the bumpers. The fix was the one a real machine already uses --
|
|
2120
|
+
the cabinet grew the rear bay the head bolts to. It is 1.34 m long instead of 1.14, its
|
|
2121
|
+
rear face and back legs moved with it, the backbox is 200 mm deep rather than 380, and
|
|
2122
|
+
the head now sits on that bay entirely behind the glass. The file's header records the
|
|
2123
|
+
repair, because the gallery makes a claim about who wrote each program and a claim
|
|
2124
|
+
quietly edited afterwards is worse than no claim.
|
|
2125
|
+
- **The vending machine's sold-out column, which read as a hole in the model.** One
|
|
2126
|
+
unlit column was meant to be the asymmetry that stops a 4 x 3 grid looking like a
|
|
2127
|
+
texture. It is, but everything in that column -- the dimmed panel, the bezel shelves,
|
|
2128
|
+
the rails -- is near-black, so instead of an empty rack behind a switched-off light it
|
|
2129
|
+
came out as a solid black rectangle with no shape in it, next to three lit columns. All
|
|
2130
|
+
four columns are stocked now, with an amber PET added as the fourth product, and the
|
|
2131
|
+
asymmetry that survives is the one that was always doing the work: cans in one column,
|
|
2132
|
+
bottles in the other three.
|
|
2133
|
+
- **The vending machine's bin label, which was a flat plate on a round drum.** A 240 mm
|
|
2134
|
+
slab across a 390 mm bin touches it along one line: the middle sinks in and both ends
|
|
2135
|
+
stand 40 mm proud, which from the front reads as a white wing growing out of the side.
|
|
2136
|
+
It is now an annular sector swept up through the label's height -- the same wedge the
|
|
2137
|
+
well's curb stones are cut from -- sitting 6 mm proud all the way round.
|
|
2138
|
+
- **`createPart` now rejects a wrong call instead of dying in the exporter.** The
|
|
2139
|
+
harness smoke run found this the way it was always going to be found: a free model
|
|
2140
|
+
on Hermes wrote `createPart(root, { name, geo, material })` -- the shape most other
|
|
2141
|
+
scene APIs take -- and the run failed 185 seconds later with `undefined is not an
|
|
2142
|
+
object (evaluating 'Object.keys(morphAttributes)')`. Nothing in that sentence names
|
|
2143
|
+
anything the model wrote, so it had no way back and spent its remaining turns
|
|
2144
|
+
guessing. `new THREE.Mesh()` accepts any two arguments at all, which is what let a
|
|
2145
|
+
function reference and a plain object travel that far. The three positional
|
|
2146
|
+
arguments are now checked at the door, and each message says which argument, what
|
|
2147
|
+
arrived, and what the call looks like when it is right: a parent passed first is
|
|
2148
|
+
told the parent belongs in the options object, `boxGeo` without parentheses is told
|
|
2149
|
+
geometry helpers have to be called, an un-awaited `roundedBoxGeo` is told the helper
|
|
2150
|
+
is async and `build()` has to be too, and a hex number where a material belongs is
|
|
2151
|
+
told to wrap it. The same program now fails in under a second with a sentence a
|
|
2152
|
+
model can act on.
|
|
2153
|
+
- **Three hero assets whose geometry was wrong in ways a contact sheet hides.** The
|
|
2154
|
+
ferris wheel braced its two A-frames together at mid-height, and the upper tie sat
|
|
2155
|
+
1.93 m from the hub inside a 3.60 m rim -- a girder straight through the spokes and
|
|
2156
|
+
the cars. It is now a clearance rule rather than a pair of chosen heights: candidate
|
|
2157
|
+
bracing levels are filtered against the wheel's swept envelope, rim radius plus how
|
|
2158
|
+
far a car hangs below its pin, and only the low portal survives, which is exactly
|
|
2159
|
+
where a real double-A-frame wheel is braced. The vending machine's cans were albedo
|
|
2160
|
+
`0x4a2f0c` at metalness 0.78; a metal has no diffuse term, so its whole appearance
|
|
2161
|
+
is a specular reflection tinted by its albedo, and a near-black albedo under a
|
|
2162
|
+
neutral studio dome returns almost nothing -- the cans rendered as black rectangles
|
|
2163
|
+
and their column read as empty stock. A printed can is a coating over the metal, so
|
|
2164
|
+
it is dielectric like the bottles, and only the bare lid is aluminium. And the
|
|
2165
|
+
lighthouse's keeper's cottage stood a plain rectangular slab on each end wall as a
|
|
2166
|
+
gable, leaving 0.91 m of stone above the slate at both eaves; the gables are now
|
|
2167
|
+
pentagons derived from the roof pitch through `extrudeProfile`, tucked 20 mm under
|
|
2168
|
+
the roof underside so the two cannot fight for the same pixel.
|
|
2169
|
+
- **An external 32,000-token ceiling was ending dispatched runs mid-thought.**
|
|
2170
|
+
OpenCode caps one assistant step at 32,000 output tokens by default, whatever the
|
|
2171
|
+
model publishes. It is not a number this project set, and it took reading its
|
|
2172
|
+
session store to see: across every step ever recorded there, nothing had exceeded
|
|
2173
|
+
32,000 -- not once, not by a token -- while the models involved declare between
|
|
2174
|
+
80,000 and 943,718. Runs stopped there mid-sentence, with no file and no error,
|
|
2175
|
+
looking exactly like a model that was not up to the work. Dispatch now sets
|
|
2176
|
+
`OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX` per run from the model's own declared
|
|
2177
|
+
limit, read out of OpenCode's model catalog, so the ceiling is the provider's and
|
|
2178
|
+
never one invented here. `docs/install.md` says how to do the same by hand.
|
|
2179
|
+
- **Removed every default cap on how much work an agent may do.** The generation
|
|
2180
|
+
budget defaulted to 40 model calls, `--max-steps` to 24, and whole-program
|
|
2181
|
+
rewrites after a first successful render to 2. All three were cost guards from a
|
|
2182
|
+
hosted product where the operator paid for the calls. Out here the person running
|
|
2183
|
+
the tool is the person paying for it, and a ceiling they did not choose stops an
|
|
2184
|
+
asset halfway for reasons that have nothing to do with the asset. All three now
|
|
2185
|
+
default to no limit -- zero was already this codebase's "unlimited" value,
|
|
2186
|
+
honoured by the call budget, the step hook and the grade-refine headroom check,
|
|
2187
|
+
so this is a default change rather than new machinery. `--max-steps` also accepts
|
|
2188
|
+
`0` now instead of rejecting the value its own help text recommends, and the
|
|
2189
|
+
rewrite bound became a per-host option so a caller who wants it can still ask.
|
|
2190
|
+
The sandbox byte limits, the procedural texture bounds and the render deadlines
|
|
2191
|
+
stay: those are safety and correctness, not cost.
|
|
2192
|
+
- **Nothing told a model to write the file before it had solved the asset.** The
|
|
2193
|
+
skill's loop said "write the program" at step two and "write the *final* program
|
|
2194
|
+
to a file" at step six, which invites a model to keep the whole thing in its head
|
|
2195
|
+
until it is finished. Some do, and never arrive: measured through OpenCode's
|
|
2196
|
+
session store, four separate runs spent their entire output allowance -- to the
|
|
2197
|
+
token -- on one unbroken reasoning block, hand-solving pin positions and cylinder
|
|
2198
|
+
attachment points in prose until they were cut off mid-number, having written
|
|
2199
|
+
nothing at all. Three different vendors' models failed this way. The loop now
|
|
2200
|
+
says to save a rough version early, says plainly not to solve the geometry
|
|
2201
|
+
analytically first, and names the failure so a model can recognise it. The
|
|
2202
|
+
dispatch brief says the same.
|
|
2203
|
+
- **Attribution rested on the request rather than on what ran.** The dispatcher
|
|
2204
|
+
stamped the model it had *asked* for, which is the one claim the gallery exists
|
|
2205
|
+
to make and the one thing it was not checking. It now reads the model back out
|
|
2206
|
+
of the harness's own output and records that, reporting the difference if the
|
|
2207
|
+
two ever disagree. No harness has been caught substituting a model -- every one
|
|
2208
|
+
of the six OpenCode runs already promoted agrees with its log -- so this closes
|
|
2209
|
+
a gap rather than a leak, and makes "nothing in the gallery is misattributed" a
|
|
2210
|
+
statement backed by a check instead of an assumption.
|
|
2211
|
+
- **Codex could never have authored an asset.** Three faults in its entry in the
|
|
2212
|
+
dispatch table, each of which fired before the model saw the brief, which is why
|
|
2213
|
+
nothing in the gallery came from it and why nothing said so. `--full-auto` is
|
|
2214
|
+
deprecated in favour of an explicit `--sandbox`. A clean room is a bare temp
|
|
2215
|
+
directory, and Codex refuses to start in one as "not inside a trusted directory"
|
|
2216
|
+
unless the git check is waived. And the sandbox was never passed at all: with no
|
|
2217
|
+
`--cd` the child ran in this repository, with every finished example in reach --
|
|
2218
|
+
the exact contamination the sandbox exists to prevent, in the one harness whose
|
|
2219
|
+
results would have been quietly worthless rather than merely absent. Its default
|
|
2220
|
+
model is now unset rather than `gpt-5.1-codex`, which that account is not entitled
|
|
2221
|
+
to and which no repository can guess; dispatch demands `--model` instead of
|
|
2222
|
+
stamping an author it cannot name.
|
|
2223
|
+
- **The dispatcher's usage line omitted OpenCode**, which had written six of the
|
|
2224
|
+
twenty-seven programs in the gallery at the time. It is generated from the harness
|
|
2225
|
+
table now, so it cannot drift from the list it describes again.
|
|
2226
|
+
- **A busy GPU renderer was read as an absent one.** `--render auto` probed
|
|
2227
|
+
`/health` with a 1.5 second budget and treated anything that was not a clean
|
|
2228
|
+
answer as "no service here". The render service is single-threaded, so while it
|
|
2229
|
+
is drawing somebody else's frame it accepts the socket and answers late, and a
|
|
2230
|
+
batch of agents pointed at one GPU had runs silently drop to the CPU rasterizer
|
|
2231
|
+
and judge their materials off a sheet where every textured surface is flat white.
|
|
2232
|
+
Nothing logged a fault, because from the caller's side nothing had failed. The
|
|
2233
|
+
probe now distinguishes the two: a refused connection still falls through at once,
|
|
2234
|
+
which is the point of the short budget on machines with no renderer at all, but a
|
|
2235
|
+
timeout is retried against an 8 second one. `src/__tests__/cli-render-mode.test.ts`
|
|
2236
|
+
holds a stand-in service to both cases and to the closed port.
|
|
2237
|
+
- **Material constructors accepted an options object as their colour.**
|
|
2238
|
+
`gameMaterial(color, options?)` takes the colour first, and a program that wrote
|
|
2239
|
+
`gameMaterial({ color, roughness, metalness })` got a white material at default
|
|
2240
|
+
roughness rather than an error: `THREE.Color.set` ignores an object it does not
|
|
2241
|
+
recognise, so the mistake survives all the way to the render, where it looks like
|
|
2242
|
+
a lighting problem. It cost a real asset an afternoon. All four constructors now
|
|
2243
|
+
refuse a non-colour first argument and say where the settings go.
|
|
2244
|
+
- **A dispatched program that outlived its own run lost its author.**
|
|
2245
|
+
`scripts/dispatch-asset.mjs` recorded the authoring model only on a clean exit,
|
|
2246
|
+
so a run that wrote a finished program and then hit a wall was scored as having
|
|
2247
|
+
produced nothing: the file was still promoted, and stamped `Authored by: null`.
|
|
2248
|
+
Which is worse than an honest partial claim, because it is not a claim at all.
|
|
2249
|
+
Three assets in this gallery were written that way. The check is now "is there a
|
|
2250
|
+
program on disk", asked before the failure is classified rather than inside one
|
|
2251
|
+
branch of it, so it covers every way a run can be cut short instead of the one
|
|
2252
|
+
that was noticed first -- a provider limit, and the dispatcher's own 25 minute
|
|
2253
|
+
deadline, both of which fire long after the program is written. The
|
|
2254
|
+
interruption is carried into the manifest and stated plainly in the file header,
|
|
2255
|
+
because a run that was cut off cannot claim it looked at its own render and
|
|
2256
|
+
revised. Separately, the rate-limit matcher knew `RESOURCE_EXHAUSTED`, `429` and
|
|
2257
|
+
`quota` but not "session limit", which is Claude Code's wording, so a batch that
|
|
2258
|
+
hit one reported three flat failures and gave up instead of falling back or
|
|
2259
|
+
waiting the window out.
|
|
2260
|
+
- **`examples/aircraft-carrier.kiln.js` wore a comb of teeth around its counter.**
|
|
2261
|
+
The hull, the flight deck and the deck-edge netting were runs of axis-aligned
|
|
2262
|
+
slabs, each held at the half-beam or the deck width of its own centre. Wherever
|
|
2263
|
+
the ship is not parallel to its own keel -- the fine entry, the whole counter, the
|
|
2264
|
+
stern round-in where the starboard edge sweeps 21 m outboard in 23 -- every join
|
|
2265
|
+
left an end cap facing aft, and an end cap is lit as a different surface from the
|
|
2266
|
+
plating either side of it. Halving the station spacing only doubled the number of
|
|
2267
|
+
teeth, because the discontinuity was in the normals and not in the size of the
|
|
2268
|
+
step. All three are now lofted along their own planform curves, which share their
|
|
2269
|
+
vertices: no cap to catch the light, no step to refine, and 7,000 fewer triangles
|
|
2270
|
+
than the slabs cost.
|
|
2271
|
+
- **Dispatched Claude runs stopped for permission with nobody to ask.**
|
|
2272
|
+
`--permission-mode acceptEdits` grants writes and nothing else, so a child that
|
|
2273
|
+
reached for `kiln_render` blocked on a prompt no terminal was attached to. Three of
|
|
2274
|
+
four runs in one batch returned after a minute having written no program, no error
|
|
2275
|
+
and exit 0 -- just a courteous note about which permissions they would need, which
|
|
2276
|
+
is the worst shape a failure can take on an unattended path. The sandbox now ships
|
|
2277
|
+
a `.claude/settings.json` allowing the Kiln MCP tools under either install name
|
|
2278
|
+
plus the file tools, scoped to the one throwaway directory rather than reaching for
|
|
2279
|
+
`--dangerously-skip-permissions`.
|
|
2280
|
+
- **A dispatch deadline that could not actually end a run.** `--timeout` fired on
|
|
2281
|
+
schedule, wrote "timed out; killed" into the log, and then called `child.kill()`,
|
|
2282
|
+
which signals the direct child and nothing beneath it. On the path that matters
|
|
2283
|
+
that child is a shell: an npm-installed CLI on Windows is a `.cmd` shim, so the
|
|
2284
|
+
agent itself is a grandchild and survived. It went on holding the stdout pipe
|
|
2285
|
+
open, `close` never fired, and the job hung after having already been declared
|
|
2286
|
+
dead -- three jobs in one batch sat between 14 and 38 minutes past a 24-minute
|
|
2287
|
+
deadline, with a concurrency slot held by each. The deadline now kills the
|
|
2288
|
+
process tree (`taskkill /T` on Windows; elsewhere the child is spawned as its own
|
|
2289
|
+
process-group leader so the group takes the signal), and the promise settles on a
|
|
2290
|
+
15-second grace timer whether or not `close` ever arrives, so a descendant that
|
|
2291
|
+
refuses to die costs one job rather than the batch.
|
|
2292
|
+
- **Orthographic views now fit what they are looking at.** The GPU render service
|
|
2293
|
+
framed every view with `max(sizeX, sizeY, sizeZ) * 0.72` -- the longest axis
|
|
2294
|
+
whichever way the camera was pointed, padded by a constant -- so anything that was
|
|
2295
|
+
not a cube rendered small in a large frame, and a long object viewed down its own
|
|
2296
|
+
axis was framed for a length nobody could see. Views are now fitted per direction
|
|
2297
|
+
by projecting the bounding box's eight corners onto the camera basis, which is
|
|
2298
|
+
exact for an orthographic projection. This also makes `--render cpu` and
|
|
2299
|
+
`--render gpu` frame identically: the CPU rasterizer has always fitted this way,
|
|
2300
|
+
and the two disagreeing meant the documented side-by-side of the two modes was not
|
|
2301
|
+
comparing the same crop. `render-service/src/framing.mjs` is the whole of it, and
|
|
2302
|
+
it is GPU-free so it is covered by unit tests.
|
|
2303
|
+
- **Unit-length normals out of `lathe()` and `revolveGeo()`.** `THREE.LatheGeometry`
|
|
2304
|
+
copies its running meridian normal into the previous-normal slot *before*
|
|
2305
|
+
normalising it, so the final ring of a revolve carried normals scaled by the length
|
|
2306
|
+
of the last profile segment -- enough to fail `GLTF_ACCESSOR_VECTOR3_NON_UNIT` on
|
|
2307
|
+
export. Both entry points now normalise before returning.
|
|
2308
|
+
- **`kiln_list_primitives` no longer sends its catalog twice.** The result carried
|
|
2309
|
+
all 92 entries as a structured array *and* as the text rendered from that array,
|
|
2310
|
+
and the default MCP serialization pretty-printed both: 90,497 bytes for one call.
|
|
2311
|
+
Harnesses disagree about results that size. OpenCode truncates them, spills the
|
|
2312
|
+
full copy to a file, and hands the model a cut-off catalog -- a dispatched
|
|
2313
|
+
`glm-5.3` run spent twenty-two minutes grepping that spill file at increasing
|
|
2314
|
+
offsets and never wrote a program. `KilnToolDef` gained an optional `text()`
|
|
2315
|
+
extractor (the text analogue of the existing `media()`), so a def whose output
|
|
2316
|
+
already contains a rendered form of itself can send that instead of a JSON dump.
|
|
2317
|
+
In-process callers still get `primitives` from `run()`. Measured after: 36,647
|
|
2318
|
+
bytes, received in full, with the same model correctly enumerating all 92
|
|
2319
|
+
primitives. `src/__tests__/mcp-payload.test.ts` holds the ceiling.
|
|
2320
|
+
- **Unit-length normals out of `subdivide()`.** `three-subdivide` builds each new
|
|
2321
|
+
vertex normal by summing the normals of the faces meeting there and never divides
|
|
2322
|
+
through, so a normal comes back at the length of however many faces touched it --
|
|
2323
|
+
2/3 after one iteration on a box, 0.35 after two. No raster shows it, because a
|
|
2324
|
+
shader normalises before it lights, but the glTF validator rejects every one of
|
|
2325
|
+
them. Found by a dispatched agent whose printing-press bed was
|
|
2326
|
+
`subdivide(boxGeo(1.5, 0.6, 0.8), 2)`: 1,104 bad normals out of 1,152, and the
|
|
2327
|
+
build stopped at final-glb. Same repair as `lathe()`.
|
|
2328
|
+
`src/__tests__/subdivide-normals.test.ts` also asserts the raw upstream call is
|
|
2329
|
+
still broken, so the workaround can be removed the day that changes.
|
|
2330
|
+
- **Explicit default scenes on exported GLBs.** Generated and composed artifacts now
|
|
2331
|
+
set the glTF default scene, and optimize/palette rewrites repair legacy files whose
|
|
2332
|
+
first scene existed without being selected. Consumers no longer have to guess which
|
|
2333
|
+
scene to mount.
|
|
2334
|
+
- **`kiln_screenshot_animation` no longer rejects every textured asset.** The tool
|
|
2335
|
+
poses the scene and exports it again to render one camera cell, and that export
|
|
2336
|
+
was being submitted to asset QA as though it were a new asset. It is not: those
|
|
2337
|
+
bytes came out of this engine and had already passed. But a texture that has been
|
|
2338
|
+
through a GLB round trip returns as a decoded image without the payload
|
|
2339
|
+
provenance `MAT_TEXTURE_DECODE_FAILED` looks for, so QA blocked the preview --
|
|
2340
|
+
meaning no textured asset could look at its own animation, including
|
|
2341
|
+
`examples/robot-arm.kiln.js`, which is the repository's designated animation
|
|
2342
|
+
example. `renderSceneToGLB` gained a `derivative` option that makes QA observe
|
|
2343
|
+
rather than block for exactly this re-serialization; reports still record their
|
|
2344
|
+
real disposition, and the option is far narrower than the process-wide
|
|
2345
|
+
`KILN_QA_MODE` escape hatch.
|
|
2346
|
+
- **Dispatched agents no longer hang after finishing their work.** `scripts/dispatch-asset.mjs`
|
|
2347
|
+
spawned children with stdin as an open pipe. OpenCode keeps its process alive while stdin is open,
|
|
2348
|
+
so a run would author the asset, write the file, and then sit there until the dispatch timeout
|
|
2349
|
+
killed it and reported a failure. Children are now spawned with stdin closed; the same command
|
|
2350
|
+
that ran to a 75-second kill exits in six.
|
|
2351
|
+
- **The dispatch sandbox is a real one.** It was created under `.dogfood/`, inside this repository,
|
|
2352
|
+
so a child agent's CLI resolved the project root by walking up to `.git` and found the whole repo,
|
|
2353
|
+
`examples/` included. It now lives in the OS temp directory.
|
|
2354
|
+
- **The MCP server no longer needs Bun on the consumer's PATH.** Every published
|
|
2355
|
+
config said `"command": "bun"`, which asks the harness to resolve a name against
|
|
2356
|
+
its own environment. Bun's Windows installer appends to the *User* PATH, and a
|
|
2357
|
+
process only ever sees the environment it was born with, so any harness started
|
|
2358
|
+
before that install died with `exec: "bun": executable file not found in %PATH%`.
|
|
2359
|
+
There is no Bun-specific API on the server's runtime path, so it now ships as
|
|
2360
|
+
`dist/mcp-server.mjs`, a committed Node bundle -- committed because a plugin install
|
|
2361
|
+
is a git clone with no build step. Bun remains the development toolchain and is no
|
|
2362
|
+
longer something a user of the plugin needs.
|
|
2363
|
+
|
|
2364
|
+
## [0.6.0] -- 2026-07-12
|
|
2365
|
+
|
|
2366
|
+
### Added
|
|
2367
|
+
- **`measureGlbBounds(bytes)` (H-41).** World-space AABB straight from stored GLB
|
|
2368
|
+
bytes (WebIO + `getBounds`, EXT_mesh_gpu_instancing registered) so consumers that
|
|
2369
|
+
only hold the artifact never need `executeKilnCode` to recover a footprint --
|
|
2370
|
+
Kiln Studio's compose catalog drops its execute-model-code bbox fallback on this.
|
|
2371
|
+
- **Six-grid rear-quarter variant (H-33 arm).** `SIX_VIEWS_REAR_QUARTER` swaps the
|
|
2372
|
+
3/4 cell to the opposite-rear azimuth (`[-0.7, 0.5, -0.7]`, labeled `3/4 Rear`);
|
|
2373
|
+
`resolveGridViews(variant)` + the `KILN_GRID_VARIANT=rear-quarter` env select it
|
|
2374
|
+
as the `renderViewGrid` default per-process -- no wire or tool-schema change.
|
|
2375
|
+
Explicit `opts.views` always wins; unknown env values fall back to `SIX_VIEWS`.
|
|
2376
|
+
- **Gemini thinking + budget knob (H-43/B1).** The `google` provider now forwards
|
|
2377
|
+
`KilnModelDescriptor.maxTokens` → `generationConfig.maxOutputTokens` and effort
|
|
2378
|
+
keywords → `thinkingConfig.thinkingLevel` ('xhigh'/'max' collapse to 'high';
|
|
2379
|
+
numbers ignored; the KILN_THINKING env stays Anthropic-only). A bare descriptor
|
|
2380
|
+
still sends nothing -- Gemini API defaults (65,536 output, dynamic thinking) are
|
|
2381
|
+
preserved unless a consumer opts in. NOTE for consumers: registry rows that
|
|
2382
|
+
carried a decorative Google `maxTokens` now BIND -- set them to the intended
|
|
2383
|
+
ceiling before upgrading.
|
|
2384
|
+
|
|
2385
|
+
### Changed
|
|
2386
|
+
- **The texture library's signal floor is now two floors instead of one.** The
|
|
2387
|
+
package-weight test asserted every map's peak channel deviation cleared 2, which
|
|
2388
|
+
worked while all eight families were rough: it was really asking "is this real
|
|
2389
|
+
photography rather than a proof swatch". Extending the library to smooth materials
|
|
2390
|
+
broke it for the right reason -- a polished marble normal map and an oak veneer
|
|
2391
|
+
normal map are *supposed* to be near-flat, and one high floor would have quietly
|
|
2392
|
+
restricted the library to rough surfaces forever. Per map the assertion is now
|
|
2393
|
+
only that the image is not constant; the photography claim is enforced per family,
|
|
2394
|
+
where it belongs.
|
|
2395
|
+
- **OpenRouter reasoning clamp (A7).** `resolveOpenRouterReasoning(thinking,
|
|
2396
|
+
maxTokens?)` now bounds reasoning by the completion budget: numeric budgets cap
|
|
2397
|
+
at 50% of `maxTokens` (dropped entirely when even the 1024 floor exceeds that
|
|
2398
|
+
half), and 'high'/'xhigh' downgrade to 'medium' when OpenRouter's ~80%
|
|
2399
|
+
translation would leave < 8,192 visible tokens (the cycle-2 step-1 MaxTokens
|
|
2400
|
+
deaths: a 32K model at 'high' kept only ~6.4K for visible output). 64K/48K
|
|
2401
|
+
configurations are untouched.
|
|
2402
|
+
- **QA-blocked render errors are actionable (H-40(3)).** `AssetQaBlockedError`'s
|
|
2403
|
+
message now spells out each blocker's human message + authored `repairText`
|
|
2404
|
+
(first 6, then a count) instead of bare rule codes -- this string is exactly what
|
|
2405
|
+
the agent reads when a mid-loop `kiln_render` is QA-blocked, and what the
|
|
2406
|
+
salvage path records for QA-blocked step-cap programs.
|
|
2407
|
+
|
|
2408
|
+
### Measured
|
|
2409
|
+
- **Per-render QA cost (H-40(4), `scripts/qa-cost-bench.ts`):** registry rules add
|
|
2410
|
+
1–10 ms p95 per render across all five category fixtures; Khronos validation
|
|
2411
|
+
(unconditional, both modes) adds 1–4 ms p95. Two orders of magnitude under the
|
|
2412
|
+
1.5 s follow-up threshold -- mid-loop QA stays on unconditionally.
|
|
2413
|
+
|
|
2414
|
+
## [0.4.0] -- 2026-07-02
|
|
2415
|
+
|
|
2416
|
+
### Added
|
|
2417
|
+
- **M1c GPU-instancing pass (plan/05 §3.3).** `renderSceneToGLB`/`renderGLB` gain an
|
|
2418
|
+
`instance: 'off' | 'auto' | 'on'` option (default `auto` = only `role: 'fill'` assets)
|
|
2419
|
+
and `optimizeGlbBytes` gains `{ instance, role }` -- the web-tier re-bake seam, so the
|
|
2420
|
+
pass reaches prod with no wire change. Repeated geometry (>= 5 nodes sharing one mesh
|
|
2421
|
+
after dedup) is rewritten to `EXT_mesh_gpu_instancing` batches in the upstream-canonical
|
|
2422
|
+
`dedup → instance → palette` order, cutting draw calls + bytes for fence runs /
|
|
2423
|
+
colonnades / container stacks. **Perf/filesize only -- the A–F grade keys on material
|
|
2424
|
+
count and does not move** (tests assert grade + triangle parity). Skipped for
|
|
2425
|
+
animated/skinned docs and any asset carrying `Joint*` pivot names (Kiln City targets
|
|
2426
|
+
those by name). Results are recorded as `InstancingSummary` (`meta.instancing`,
|
|
2427
|
+
`RenderSceneResult.instancing`, `OptimizeGlbResult.instancing` -- and
|
|
2428
|
+
`OptimizeGlbResult.summary` is now optional: an instancing-only pass has no
|
|
2429
|
+
consolidation summary). All engine glTF IO now registers `EXTMeshGPUInstancing`
|
|
2430
|
+
(new dep `@gltf-transform/extensions`) so re-reads (grade-from-bytes,
|
|
2431
|
+
optimize-from-bytes, palette snap, scene export merge) preserve the batches, and
|
|
2432
|
+
`collectGlbMetrics` is instance-aware (an instanced node counts one draw but N× its
|
|
2433
|
+
triangles -- exactly what a supporting GPU renders).
|
|
2434
|
+
- **M3 composer role/tier awareness (plan/05 §4.1).** `CatalogEntry` gains optional
|
|
2435
|
+
`role` (`CatalogAssetRole` -- the M1d asset taxonomy) + `tier` (A–F); `catalogList()`
|
|
2436
|
+
(and therefore `scene_list_assets`) surfaces them. Placement roles now DEFAULT from
|
|
2437
|
+
the catalog asset's role via `placementRoleForAsset` (wonder/poi → hero, fill → fill,
|
|
2438
|
+
else support) in `place`/`placeExact`/`cluster`/`ring`/`layout` -- an explicit agent
|
|
2439
|
+
role still wins. The composer system prompt teaches the mapping, wonder scale-up, and
|
|
2440
|
+
D/F-tier density budgeting.
|
|
2441
|
+
|
|
2442
|
+
## [0.3.0] -- 2026-07-02
|
|
2443
|
+
|
|
2444
|
+
### Added
|
|
2445
|
+
- **Generation-loop transcript compaction (default on).** Before every model call,
|
|
2446
|
+
`runKilnAgent` now strips the image out of each SUPERSEDED render tool result
|
|
2447
|
+
(kiln_render / kiln_screenshot / kiln_view_interior / animation strips), swapping it for
|
|
2448
|
+
a short text placeholder -- only the newest render image rides each request. The prune is
|
|
2449
|
+
surgical, unlike the composer's whole-transcript collapse: no messages are added or
|
|
2450
|
+
removed, toolUseIds are untouched (tool-use/tool-result pairing stays valid on every
|
|
2451
|
+
provider), and the JSON metrics half of each result survives. This was the biggest
|
|
2452
|
+
input-token/cost lever in a multi-render run -- previously every render image rode ALL
|
|
2453
|
+
later model calls. Opt out per run with `imageCompaction: 'off'`. New helpers exported
|
|
2454
|
+
from `agent`: `pruneStaleRenderImages`, `installRenderImageCompaction`,
|
|
2455
|
+
`STALE_RENDER_PLACEHOLDER`.
|
|
2456
|
+
- **M1b grade-aware refine loop (plan/05 §3.2, default on).** After the model finalizes,
|
|
2457
|
+
the run bakes + grades the program exactly as the shipped artifact will be graded
|
|
2458
|
+
(grade-aware `auto` consolidation, matching `generateKilnAsset` and the Studio web-tier
|
|
2459
|
+
re-bake). If it still grades below B for a consolidation-fixable reason -- material
|
|
2460
|
+
sprawl (>3 distinct) or texture sprawl (>4), never a transparency-only demotion (glass
|
|
2461
|
+
caps at C by design) -- and the step budget leaves headroom, ONE bounded feedback turn
|
|
2462
|
+
(grade, material count, offending material list, consolidation directive) is fed back;
|
|
2463
|
+
the refined program is kept only if its grade actually improves. Opt out with
|
|
2464
|
+
`gradeRefine: 'off'`. Emits a `grade_refine` progress event; token usage now accumulates
|
|
2465
|
+
across the extra invoke. New helpers exported from `agent`: `assessProgramGrade`,
|
|
2466
|
+
`shouldGradeRefine`, `buildGradeRefineMessage`, `gradeRank`.
|
|
2467
|
+
|
|
2468
|
+
### Fixed
|
|
2469
|
+
- **Step-cap abort no longer discards a rendered program.** A run halted by the model-call
|
|
2470
|
+
cap used to return only an error, throwing away the working-buffer program the sink
|
|
2471
|
+
already held. If the captured program renders, the run now returns it with the new
|
|
2472
|
+
`RunKilnAgentResult.capped: true` flag (mirrors the composer's `capped` semantics); a
|
|
2473
|
+
cap with nothing renderable is still an `error`.
|
|
2474
|
+
|
|
2475
|
+
## [0.2.0] -- 2026-07-02
|
|
2476
|
+
|
|
2477
|
+
The release cut the 0.1.1 composer note promised: formally versions the scene composer
|
|
2478
|
+
surface (`@kiln/engine/composer`, `/composer/agent` -- shipped in 0.1.x without a bump)
|
|
2479
|
+
plus the fixes below.
|
|
2480
|
+
|
|
2481
|
+
### Fixed
|
|
2482
|
+
- **`auto` consolidation now fires on 4-material assets.** `PALETTE_MIN` dropped 5 → 4,
|
|
2483
|
+
aligning the trigger with the instanceability rubric (grade B tops out at 3 materials,
|
|
2484
|
+
so 4 is the first grade-C count). Previously a 4-material asset graded C and `auto`
|
|
2485
|
+
never consolidated it.
|
|
2486
|
+
- **Uint32 indices for >65,535-vertex geometry.** `bridgeGeometry` always wrote
|
|
2487
|
+
`Uint16Array` indices, silently wrapping values past 65,535 (corrupt GLB). It now
|
|
2488
|
+
selects `Uint32Array` when the vertex count exceeds the Uint16 ceiling; the GLB
|
|
2489
|
+
writer emits the matching `componentType` (5125).
|
|
2490
|
+
- **BYOK `apiKey` reaches Anthropic/OpenAI.** `makeKilnModel` dropped `opts.apiKey` on
|
|
2491
|
+
the `anthropic` and `openai` branches (only google/openrouter passed it through), so
|
|
2492
|
+
BYOK silently fell back to the provider env vars.
|
|
2493
|
+
|
|
2494
|
+
### Changed
|
|
2495
|
+
- Comments in `agent/tools.ts` / `agent/run.ts` updated: the `unified` tool surface is
|
|
2496
|
+
the production surface (Kiln Studio runs `KILN_TOOL_SURFACE=unified`), no longer
|
|
2497
|
+
"flag-gated until a bench A/B clears it"; `current` remains the library default.
|
|
2498
|
+
|
|
2499
|
+
### Housekeeping
|
|
2500
|
+
- Added the missing `LICENSE` file (MIT, already declared in `package.json`).
|
|
2501
|
+
- Rewrote the stale `@pixel-forge/core` module headers (`metrics.ts`, `agent/index.ts`,
|
|
2502
|
+
`agent/run.ts`, `palette.ts`) to the `@kiln/engine` reality and removed dangling
|
|
2503
|
+
references to files that do not exist in this repo.
|
|
2504
|
+
|
|
2505
|
+
## [0.1.1] -- 2026-06-30
|
|
2506
|
+
|
|
2507
|
+
### Documentation
|
|
2508
|
+
- Clarified that `@kiln/engine` remains private execution infrastructure. External developer access
|
|
2509
|
+
is mediated by Studio `/v1`, private SDK/skills, and future AgentCore Gateway product tools rather
|
|
2510
|
+
than direct engine, raw Forge, or composer harness exposure.
|
|
2511
|
+
|
|
2512
|
+
### Changed
|
|
2513
|
+
- Treat native `claude-sonnet-5` as adaptive-only for Anthropic thinking controls: numeric
|
|
2514
|
+
`KILN_THINKING` budgets are ignored for this model so the agent harness does not send
|
|
2515
|
+
manual extended-thinking params that Sonnet 5 rejects.
|
|
2516
|
+
|
|
2517
|
+
### Added -- scene composer (`@kiln/engine/composer`, `/composer/agent`)
|
|
2518
|
+
A THREE-free scene-composition surface: a `PlacementModel` single-source-of-truth with a
|
|
2519
|
+
small scene DSL (`scene()`/`asset()`), terrain-agnostic hierarchy-aware layout, an overlap
|
|
2520
|
+
validator (MTV resolution), a ground sampler, and a `SceneRenderPort`; plus the Strands
|
|
2521
|
+
agent loop (`runKilnComposer`, 14 `scene_*` tools) isolated under `/composer/agent` so the
|
|
2522
|
+
SDK never leaks into the pure core. Transcript compaction collapses to `serialize(model)`
|
|
2523
|
+
past a threshold (the externalized model IS the state), with a soft step-cap backstop and a
|
|
2524
|
+
`scene_layout`-first prompt so large many-asset scenes converge. ~990 lines of new tests.
|
|
2525
|
+
|
|
2526
|
+
> The surface landed without a version bump (Studio consumed it via the committed
|
|
2527
|
+
> `@kiln/engine` 0.1.0 tarball); formally versioned by the 0.2.0 release above.
|
|
2528
|
+
|
|
2529
|
+
## [0.1.0] -- 2026-06-23
|
|
2530
|
+
|
|
2531
|
+
Initial extraction of the Kiln 3D engine from `pixel-forge/packages/core/src/kiln`
|
|
2532
|
+
(source `d396c10`), file history preserved via `git subtree split`.
|
|
2533
|
+
|
|
2534
|
+
### Included (the reachable runtime closure of agent/render/palette/views/arena)
|
|
2535
|
+
- `agent/` Strands agent loop · `arena/` ranking math · `render.ts` GLB bake/grade/optimize/snap/composeScene
|
|
2536
|
+
- `primitives.ts` · `solids.ts` (CSG) · `ops.ts` · `gears.ts` · `uv.ts`/`uv-shapes.ts` · `textures.ts`
|
|
2537
|
+
- `validation.ts` (AST) · `inspect.ts` · `metrics.ts` · `palette.ts`/`palette-snap.ts`
|
|
2538
|
+
- `list-primitives.ts` · `prompt.ts`/`prompt-api.ts` · `tools/registry.ts` · `views/` (CPU rasterizer + PNG)
|
|
2539
|
+
|
|
2540
|
+
### Removed vs pixel-forge core/kiln (what makes it lean)
|
|
2541
|
+
- TIJ pipeline modules `imposter/`, `fbx-ingest/`, `sprite-atlas/`, `retex/`,
|
|
2542
|
+
`photogrammetry/`, `lod/` -- the only modules pulling in Playwright + the heavier
|
|
2543
|
+
image path.
|
|
2544
|
+
- Legacy single-shot `generate.ts` (Studio uses the agent path) and the entangled root
|
|
2545
|
+
`index.ts` barrel (Studio consumes subpaths, not the barrel).
|
|
2546
|
+
- Dropped deps: `@anthropic-ai/*`, `@ai-sdk/{anthropic,google,openai}`, `@google/genai`,
|
|
2547
|
+
`openai`, `@fal-ai/client`, Vercel `ai`, `playwright`, `meshoptimizer`, `xatlas-three`,
|
|
2548
|
+
`@pixel-forge/shared`.
|
|
2549
|
+
|
|
2550
|
+
### Retained runtime deps (lazy-loaded)
|
|
2551
|
+
- `sharp` -- texture decode in `loadTexture` (`await import('sharp')`).
|
|
2552
|
+
- `xatlasjs` -- UV atlas in `autoUnwrap` (`await import('xatlasjs/dist/node/...')`).
|
|
2553
|
+
|
|
2554
|
+
### Tests
|
|
2555
|
+
- 36 source test files ported (382 pass / 2 skip / 0 fail offline). Live agent tests
|
|
2556
|
+
gated behind `KILN_SPIKE_LIVE=1` (off in CI). Dropped: the 6 OUT-module test suites,
|
|
2557
|
+
`deps-smoke` (old dep set), `spike`/`top-level-generate` (tested the deleted barrel
|
|
2558
|
+
`generate()` wrapper), and `companions`/`refactor-validation` (tested the legacy
|
|
2559
|
+
`generate.ts` companion aliases `kiln.editCode`/`kiln.refactor`, also pruned).
|
|
2560
|
+
- Provider SDKs (`@anthropic-ai/sdk`, `@google/genai`, `openai`, `ai`,
|
|
2561
|
+
`@aws-sdk/client-bedrock-runtime`) are **devDependencies only** -- needed to exercise
|
|
2562
|
+
the multi-provider `makeKilnModel` factory in `providers.test.ts`; they never enter
|
|
2563
|
+
runtime `dependencies`. The kiln-glb skill-drift gate is `skipIf`-guarded (the skill
|
|
2564
|
+
lives outside the engine repo).
|
|
2565
|
+
|
|
2566
|
+
### Tooling
|
|
2567
|
+
- **Biome 2.5.1** adopted (lint + format). Source formatted to Biome style (single
|
|
2568
|
+
quotes, 2-space, 100-col); `bun run lint` is green. A baseline of 19 stylistic
|
|
2569
|
+
warnings (`noExplicitAny`/`useTemplate`/`useOptionalChain`/`noGlobalIsFinite`/…) is
|
|
2570
|
+
left visible for a hardening pass; `noNonNullAssertion`/`useLiteralKeys` are off and
|
|
2571
|
+
`useIterableCallbackReturn` is warn (all idiomatic in the extracted code).
|
|
2572
|
+
|
|
2573
|
+
### Follow-ups (deliberately deferred from WS0 -- see ../plan/03-standards-harness.md)
|
|
2574
|
+
- Burn down the 19 Biome warnings + re-promote `useIterableCallbackReturn` to error.
|
|
2575
|
+
- Tighten `tsconfig` (`exactOptionalPropertyTypes`); currently mirrors pixel-forge core
|
|
2576
|
+
for a zero-drift green typecheck.
|
|
2577
|
+
- Consider `tsup` `dist` build + Vitest golden-image render harness (engine ships TS
|
|
2578
|
+
source today for drop-in parity with how Studio consumes core).
|
|
2579
|
+
- Rename the live-test gate `KILN_SPIKE_LIVE` → `KILN_LIVE`.
|