Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
* text=auto eol=lf

contracts/backend-agent-contract.json text eol=lf
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ jobs:
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm run check:release
- run: npm ci
- run: npm run check:release
- run: npm run typecheck
- run: npm run build
- run: npm test
- run: npm run test:hygiene
- run: npm run test:package
3 changes: 3 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ jobs:
run: |
git merge-base --is-ancestor HEAD origin/main
node scripts/check-release.mjs > release-notes.md
node scripts/check-release-provenance.mjs
- run: npm install -g npm@11.20.0
- run: npm ci
- run: npm run typecheck
- run: npm run build
- run: node scripts/check-descriptions.mjs
- run: npm test
- run: npm run test:hygiene
- run: npm audit --omit=dev --audit-level=high
- run: npm run test:package
- name: Build release artifact
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ and the package adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.3.16] - 2026-10-11

### Changed

- Tool definitions, schemas, HTTP adapters and guidance are generated from the backend-owned agent contract, with hash and source parity checks. Exports include backend contract provenance.
- Shorter tool text preserves existing names, input/output schemas and annotations. Shared instructions and explicit scope metadata are available to consumers.
- Manager scope prose renders from the same metadata, including checkout ownership and deployment implied by kit-install settings.
- Detailed decision and hybrid interpretation accompanies classified `worker_run` and `run_get` results, reducing catalog repetition. `toolDocumentation` retains the full text for offline help and REST; pre-call warnings stay in tool descriptions. Raw response data is unchanged.

### Fixed

- Guidance keeps restricted-key 404 results uncertain, distinguishes human-approved spending ceilings from fleet budgets, and explains hybrid wallet charges and linked follow-on runs accurately.
- Restored model-alias resolution, classification wait restrictions, install-answer behavior, publisher bio limits and kit-edit/deletion consequences from the REST contract. REST-only long polling remains separate from MCP inputs.

## [0.3.15] - 2026-10-10

### Added
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Deliberately MCP-free: descriptors carry MCP-shaped annotations and zod schemas,
but nothing here depends on an MCP SDK, so an MCP server, a CLI, or docs tooling
can all consume the same registry.

## Contract ownership

Tool definitions, schemas, HTTP mappings and agent guidance are authored by the WorkerKit backend. Core distributes a generated, versioned copy to MCP and CLI consumers. Live catalog and account data comes from backend endpoints.

To update the contract, import the reviewed backend `Data/AgentContract.json` with `npm run import:contract -- <artifact-path>`. Commit the pinned artifact and generated modules together. `npm run check:contract` and every build reject manual changes to generated modules. Core owns the HTTP client and execution engine; tool-specific behavior is part of the backend contract.

Adapters advertise each descriptor's `description` and render its `footer` with applicable results. For full offline help or REST documentation, use `toolDocumentation(descriptor)`: it includes result interpretation without requiring an API call. Raw JSON response bodies remain unchanged.

## Install

```bash
Expand Down Expand Up @@ -166,8 +174,22 @@ npm ci
npm test # descriptor-contract suite
npm run typecheck
npm run build
npm run check:descriptions # rebuild, then report size and guidance warnings
```

`check:release` includes the fresh description report. For the complete per-tool
report, run `npm run build` then `node scripts/check-descriptions.mjs --json`.
An optional `--baseline <report.json>` compares reports made with the same
projection and tokenizer. This is a transport-neutral core projection; the MCP
repository separately checks real SDK metadata and reviewed growth budgets.
Size, uppercase and unattributed repeated-clause findings are review warnings,
never truncation instructions. Generated shared guidance is attributed by its
canonical identifier; other repeated text still needs contextual review.
Publishing also runs `check:provenance`: the pinned backend artifact must name
its reviewed 40-character source commit and match the generated modules.
Local `working-tree-*` artifacts remain usable for development and package
smoke tests, but cannot pass this publication gate.

Issues and pull requests are welcome. Every tool is a declarative `ToolDescriptor`;
the descriptor-contract tests pin each one's exact wire call, so behavior changes
are visible in the diff. Security reports go to [SECURITY.md](SECURITY.md), not the
Expand Down
3,578 changes: 3,578 additions & 0 deletions contracts/backend-agent-contract.json

Large diffs are not rendered by default.

79 changes: 46 additions & 33 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 13 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@workerkit/core",
"version": "0.3.15",
"version": "0.3.16",
"description": "API client and tool descriptors for WorkerKit: manage AI workers and browse the public kits directory",
"type": "module",
"license": "MIT",
Expand Down Expand Up @@ -45,13 +45,18 @@
"access": "public"
},
"scripts": {
"build": "node -e \"require('node:fs').rmSync('dist', {recursive:true, force:true})\" && tsc -p tsconfig.json",
"build": "npm run check:contract && node -e \"require('node:fs').rmSync('dist', {recursive:true, force:true})\" && tsc -p tsconfig.json",
"typecheck": "tsc --noEmit -p tsconfig.test.json",
"test": "vitest run",
"prepublishOnly": "npm run check:release && npm run typecheck && npm run build && npm test",
"check:release": "node scripts/check-release.mjs",
"prepublishOnly": "npm run check:provenance && npm run check:release && npm run typecheck && npm run build && npm test && npm run test:hygiene",
"check:release": "node scripts/check-release.mjs && npm run check:descriptions",
"check:descriptions": "npm run build && node scripts/check-descriptions.mjs",
"check:provenance": "node scripts/check-release-provenance.mjs",
"test:package": "node scripts/test-package.mjs",
"prepack": "npm run build"
"prepack": "npm run build",
"test:hygiene": "node --test scripts/hygiene-checks.mjs",
"import:contract": "node scripts/import-backend-contract.mjs",
"check:contract": "node scripts/import-backend-contract.mjs --check"
},
"engines": {
"node": ">=22.0.0"
Expand All @@ -62,7 +67,9 @@
},
"devDependencies": {
"@types/node": "22.20.1",
"js-tiktoken": "1.0.21",
"typescript": "5.9.3",
"vitest": "4.1.11"
"vitest": "4.1.11",
"zod-to-json-schema": "3.25.2"
}
}
51 changes: 51 additions & 0 deletions scripts/check-descriptions.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { allDescriptors, toolsForProfile, instructionsByProfile, guidance, backendContractProvenance, z } from "../dist/index.js";
import { zodToJsonSchema } from "zod-to-json-schema";
import { measureSurface } from "./measure-descriptions.mjs";

// This measures a freshly built, transport-neutral descriptor projection. The
// MCP repository separately measures real SDK initialize/tools-list output and
// enforces reviewed growth budgets, including transport metadata.
const uppercaseTerms = {
API:"API terminology", HTTP:"HTTP protocol", HTTPS:"HTTPS protocol", JSON:"JSON format",
UTC:"UTC timezone", IANA:"Timezone database", UUID:"UUID identifier", GUID:"GUID identifier",
URL:"URL format", URLs:"URL format", ISO:"Date format", RFC:"Protocol references",
MCP:"Model Context Protocol", LLM:"Language model", BYOK:"Billing mode",
GET:"HTTP method", POST:"HTTP method", PUT:"HTTP method", PATCH:"HTTP method", DELETE:"HTTP method",
XOR:"Exclusive inputs", AND:"Filter conjunction", OR:"Alternative requirements",
RUNTIME_NOT_ENABLED:"Runtime gate wire code", OPERATION_NOT_ALLOWED:"Authority wire code",
};
const sharedText = Object.fromEntries(Object.entries(guidance).map(([id,text])=>[`guidance.${id}`,text]));
const surfaces = Object.fromEntries(Object.entries(instructionsByProfile).map(([profile,instructions])=> {
const tools = toolsForProfile(profile).map(d=>({name:d.name,title:d.title,description:d.description,
inputSchema:zodToJsonSchema(d.strictInput ? z.object(d.schema).strict() : z.object(d.schema), {target:"jsonSchema7",$refStrategy:"none"}),
...(d.outputSchema ? {outputSchema:zodToJsonSchema(z.object(d.outputSchema), {target:"jsonSchema7",$refStrategy:"none"})} : {}),
annotations:d.annotations,
}));
return [profile,measureSurface({tools,instructions},{sharedText,uppercaseTerms})];
}));
const report = {schemaVersion:1,kind:"core-descriptor-projection",provenance:backendContractProvenance,
tokenizer:{package:"js-tiktoken",version:"1.0.21",encoding:"o200k_base"},
note:"Fresh core output, excluding MCP transport metadata. Size, duplication and uppercase findings are advisory. Unattributed repetitions require review; they are not automatically redundant.",surfaces};
const baselineIndex = process.argv.indexOf("--baseline");
if (baselineIndex >= 0) {
const path = process.argv[baselineIndex+1];
if (!path) throw Error("--baseline requires a prior report path");
const baseline = JSON.parse(readFileSync(resolve(path),"utf8"));
if (baseline.kind !== report.kind || baseline.tokenizer?.version !== report.tokenizer.version || baseline.tokenizer?.encoding !== report.tokenizer.encoding)
throw Error("Baseline must use the same projection and tokenizer; do not compare it to an MCP capture");
report.deltas = Object.fromEntries(Object.entries(surfaces).map(([profile,current])=> {
const previous = baseline.surfaces[profile];
if (!previous) throw Error(`Missing baseline profile: ${profile}`);
return [profile,Object.fromEntries(["catalogChars","catalogTokens","instructionsChars","instructionsTokens","descriptionChars","inputSchemaChars","parameterDescriptionChars"].map(key=>[key,current[key]-previous[key]]))];
}));
}
if (process.argv.includes("--json")) console.log(JSON.stringify(report,null,2));
else for (const [profile,r] of Object.entries(surfaces)) console.log(JSON.stringify({profile,projectionTokens:r.catalogTokens,
instructionsTokens:r.instructionsTokens,descriptionChars:r.descriptionChars,schemaChars:r.inputSchemaChars,
parameterDescriptionChars:r.parameterDescriptionChars,fourCharEstimate:r.fourCharsPerTokenEstimate,
oversized:r.oversized,exposureWarnings:r.descriptionExposureWarnings,
repeatedClauses:r.duplicates.length,attributedRepeatedClauses:r.duplicates.filter(d=>d.owners.length).length,
uppercaseWarnings:r.shouting.length,...(report.deltas ? {delta:report.deltas[profile]} : {})}));
if (new Set(allDescriptors.map(d=>d.name)).size !== allDescriptors.length) throw Error("Duplicate canonical tool");
9 changes: 9 additions & 0 deletions scripts/check-release-provenance.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { validateContract, syncContract } from "./import-backend-contract.mjs";

const contract = validateContract(JSON.parse(readFileSync(new URL("../contracts/backend-agent-contract.json",import.meta.url),"utf8")));
assert.match(contract.sourceRevision,/^[a-f0-9]{40}$/,
"Publishing requires the reviewed backend source commit, not working-tree provenance. Release backend first, then import its exact artifact.");
syncContract(contract,true);
console.log(`Backend source ${contract.sourceRevision}; payload ${contract.contentHash}`);
Loading
Loading