tosijs/agent

Everything that describes an app to a non-human user, behind one door:

import { enableAgentInterface } from 'tosijs/agent'

// nothing is exposed until you say so
const agent = enableAgentInterface({ expose: { roots: ['app'] } })
agent.describe()                       // the affordance map
export what
enableAgentInterface the surface: describe / read / write / observe / call / changes / when / log
webmcpTools, webmcpAdapter the generated WebMCP tool set (auto-registered by enableAgentInterface where a host exists)
schematicSVG, rasterizeSVG, boundsOf the map, drawn (from tosijs-floorplan, vendored)
schematic the same map as DATA (boxes, legend, note) instead of an SVG string
isInteractive, targetSizeFinding, TARGET_SIZE_DEFAULT the shared affordance rules, over a SchematicRecord from describe() — not over a DOM element. isInteractive(someAnchor) compiles in plain JS and is meaningless.
auditAccessibility, auditFlags, contrastRatio findings over the map
exerciseContract, exerciseComponent contracts as tests

These ARE the audit's rules. Since tosijs-floorplan 0.5.0 there is no divergence and no private adjustment: the three carve-outs audit.ts used to apply (ignore producer flags, exempt 0×0, treat a list-bound element carrying direct evidence as a control — tosijs-floorplan #7/#8/#9) are folded into the shared rule, and auditAccessibility() calls these exports raw.

The one knob is targetSizeFinding's honorProducerFlags, which defaults to false — the lint's answer, where a producer-supplied target-ish flag does not stand the geometry check down. schematic() opts in (honorProducerFlags: true) so a drawing never double-marks a finding it has already painted. So the default is the AUDIT's verdict, and the renderer is the one that adjusts.

(Earlier releases said the opposite here, and said it while pointing at a private auditView that no longer exists. If you are working from a cached copy of this page: the exports and the audit agree.)

Why a subpath and not the main entry. The agent surface costs roughly 15 kB gzipped, measured marginally — the same ESM bundle built from index.ts and from index-browser.ts, which is this library minus the agent surface by construction. An app that never describes itself should not carry it. Bundler users would shake it out — but the IIFE (CDN, <script>, our own doc pages) cannot, and that is the most-loaded artifact we publish. Keeping it here means the cost falls only on consumers who opt in, and the default bundle stays roughly where 1.7.x left it.

For the current number, read README — its figure is generated by bun run build, which prints both on every run. Two are worth telling apart: the marginal cost above, and the larger module.js − core.js delta, which is a different question because core also drops blueprints, share/sync and hotReload and so charges their bytes to the agent surface.

This paragraph deliberately states no digits. Three hand-typed figures here said 11 kB for four releases while the truth drifted past 15, and the correction that replaced them was itself wrong — divided by 1000 instead of 1024, so its own two operands did not subtract to its own answer.

ComponentMap (the static contract shape) is exported from both tosijs and here: declaring a contract is a component-authoring act that must not require importing the agent surface. It is type-only, so it costs nothing either way.