Skip to content

Release 0.80.0 — a capability the deployment does not have - #23

Merged
JimmyWesley merged 5 commits into
mainfrom
develop
Sep 12, 2026
Merged

JimmyWesley merged 5 commits into
mainfrom
develop

Conversation

@JimmyWesley

@JimmyWesley JimmyWesley commented Sep 11, 2026 •

Copy link
Copy Markdown
Owner

Release 0.80.0 — a capability the deployment does not have

One spec version, v0.80, and the package moves 0.79.0 → 0.80.0. It comes
from a sentence Part G has carried since v0.9: UIs and bots are MCP/library
clients, not plugins.
The line was drawn correctly and it left a whole
class of work with nowhere to stand: transcribing audio, converting a format
nobody here has heard of, reading a proprietary export. Not a client, not a
contract change, a capability this deployment simply lacks. Each arrives
with a dependency, and the dependency is the problem: FFmpeg is GPL or LGPL
depending on the build, a converter drags a machine-learning stack, a
transcriber drags another. LICENSING.md splits this tree Apache-2.0 /
AGPL-3.0-only, and that split holds only while the dependency list stays
clean. Pinning any of them makes this project their distributor.

What changed

Part L, extensions (new). An extension is a package that contributes at
named seams and never patches: converters (read by the Gardener above
extra_converters and below an operator's own command hook), curation,
events (on the one emitter that already decides webhooks), tools (on the
MCP menu), routes (under /v1/ext/<id>/), jobs (pulled, never
scheduled), ranking (inside harvest, before the budget), prompt, and
roles. register(api) is enumerated the way ScopedVine is: a new engine
capability needs its own line before an extension can reach it. A handler
marked heavy runs in the extension's own environment and its own process,
which is what keeps the motivating dependency out of the process that
serves the forest.

This project distributes nothing. Four sources (curated index, git,
archive, local file) resolve through one resolver, and whatever the source,
it becomes an immutable artifact before it is validated: a git ref becomes
a commit SHA, because a tag can be force-pushed and the thing that was
signed must be the thing that runs. A moving ref is allowed and marked
tracking, unverified by construction. Three tiers, verified from the
index, signed from a signed tag checked against the forge's published
keys, unverified for everything else. Resolving requirements.txt
executes third-party build code, so the conformance kit runs before
anything is registered, and never before third-party code runs. The
documentation says so in those words.

The mechanism is the engine's, the governance is the Station's. An
operator with no Station installs extensions from the CLI: vine ext install|update|list|remove|config|enable|disable. Global install is a
host-level directory (MONKEYLLM_EXT_HOME); per-forest enablement is
_meta/extensions.yaml, so it is versioned, travels in a snapshot, and
validate reports an extension a forest expects and does not have. _meta
declares expectation and never grants it, and a declared secret may not be
written there.

Inert and named, never an error. A contribution the host cannot serve is
listed as inert. The config schema is the source of truth and a panel is
decoration over it, enforced by the kit, so a console-less host stays
first-class. The console surface is declarative, because J.5.13 admits no
third-party script in the console's origin and that rule is not relaxed for
an extension. Studio gains an Extensions console.

Amends J.4.2, J.10, J.5. The audit row gains via (ext:<id>,
nullable, absent on rows written before this version) while principal
stays whoever caused the act: a forensic question is who asked for this,
and an extension is not an answer to it. A model role gains a kind
(chat/embed/vision/transcribe/rerank), and an extension registers
a role rather than carrying a key: it is handed a bound caller, never an
endpoint or a credential, so its spend is configured, metered and audited
where all other spend is. Quota is per extension per forest and exhaustion
is a refusal, never silence.

The first real extension. extensions/whisper registers the
transcribe role and turns a recording into a media node whose body is
the transcript, so sniff finds a word that was only ever spoken. It adds
no package to the engine's environment, which is the point of it.

Three things caught before release, kept in the task file. The loader
executed an extension's module twice (once for register, once per
handler), so module-level state split in half with no error; it now imports
once per installed tree. The extension list was gated on "has a grant"
where it meant "is admin", caught by the route canary in
test_station_admin_scope. And the MCP tools/list filter's fallback
returned the unfiltered list on an SDK shape it did not recognise; a
visibility filter fails closed.

Also in this release

  • The demo harness reads the model's own tool syntax. MiniCPM5-2B
    sometimes emits a tool call in its native XML-like function syntax
    instead of the JSON the prompt asks for; parse_action now translates
    it, typed by the engine's signature table, with no navigation help. With
    it, the 2B scores 18/18 (v2), 11/11 (v3), 7/8 (v4) on the bench
    forest with BM25-only entry search, the same scores as the 12B rows.
  • Paper 1.1.0. New §5.4 records that replication with its caveats (one
    run per set, wall-clock not comparable, navigator arm only); abstract,
    setup, Forest Principle, limitations and quickstart updated.

Leftovers, named

  • F.194 (signed-tag verification against the forge's published keys) is
    implemented and not measured.
  • The curated index is not published yet.
  • The Extensions console has had no real-browser pass.
  • F.169's curator measurement is still pending from 0.75.

Acceptance

F.174 – F.198. Full suite green locally on the release commit (1816 passed,
0 skipped, Python 3.12) and running in CI on this PR; python -m build +
twine check passed (wheel 243 kB, sdist 562 kB; the wheel carries
monkeyllm/extensions/ and cli_ext.py, and nothing of the Station).

Spec v0.80 cuts Part L, extensions. Part G has said since v0.9 that UIs
and bots are MCP/library clients, not plugins, and that sentence left a
whole class of work with nowhere to stand: a transcriber, a converter for
a format nobody here has heard of, an OCR pass, each arriving with a
dependency that LICENSING.md's Apache/AGPL split cannot pin without
making this project their distributor.

An extension is a package that contributes at named seams (L.3) and never
patches; register(api) is enumerated like ScopedVine; a heavy handler
runs in its own environment and process (L.5). This project distributes
nothing (L.0, L.2): four sources through one resolver, every one resolved
to an immutable artifact before it is validated, three trust tiers, and
the conformance kit runs before anything is registered, never before
third-party build code runs. The mechanism is the engine's and the
governance is the Station's (L.12); a contribution the host cannot serve
is inert and named (L.10); the console surface is declarative (L.11).
Amends J.4.2 (the audit row's via), J.10 (roles carry a kind, an
extension registers a role and never holds a key) and J.5 (the
Extensions console). Acceptance F.174-F.198.

tasks/T18 records the decisions, the costs accepted and what remains:
F.194's gpg measurement, the curated index, the console's browser pass.

Signed-off-by: Jimmy Wesley <rededown@hotmail.com>
The v0.80 Part L runtime: src/monkeyllm/extensions (manifest, sources,
installer, store, loader, worker, conformance kit, forest config), the
vine ext CLI (install, update, list, remove, config, enable, disable),
the Station's governance and /v1/ext routes, the Studio Extensions
console with its three catalogues, and all ten L.3 seams wired where the
host that declares each one reads it: converters in the Gardener,
curation after the host's hooks, events on the one emitter that decides
webhooks, tools on the MCP menu, routes, jobs, ranking inside harvest
before the budget, prompt on both modes, roles beside every other
binding. Audit rows gain via; roles gain kind; quota is per extension per
forest and exhaustion is a refusal.

extensions/whisper is the first real extension: it registers the
transcribe role and turns a recording into a media node whose body is
the transcript, adding no package to the engine's environment.

Three things caught before release and kept in the task file: the loader
executed a module twice, so module-level state split in half with no
error (it imports once per installed tree now); the extension list was
gated on "has a grant" where it meant "is admin", caught by the route
canary; and the tools/list filter's fallback returned the unfiltered
menu on an unrecognised SDK shape, which a visibility filter must never
do. pyproject declares an empty extensions extra as the name a future
dependency lands under, so a plain install keeps loading with the loader
inert. CLAUDE.md carries the entry. Tests: tests/test_v080_*.py.

Signed-off-by: Jimmy Wesley <rededown@hotmail.com>
MiniCPM5-2B, asked for one JSON object per turn, answers in JSON on most
turns and on some falls back into the function syntax it was trained on:
<function name="locate"><param name="query">x</param></function>. Its
reasoning picks the right tool and the right branch; only the spelling is
wrong, and bouncing it with "Invalid format" makes it repeat the spelling
until the step budget is gone. On the Phase-0 fixture that was 7/10 with
the three misses at zero tool calls each.

parse_action now translates that syntax into the same action. Each
argument is read by the type the engine's signature table declares for
it, so k is an integer, terms and filter are a list and an object, and
query="2026" stays the string it is; null is None; a value that cannot
be read as its type is left as text for the primitive to refuse. No
navigation help is added. With nothing else changed the fixture scored
10/10 on two consecutive runs, and the bench forest 18/18 (v2), 11/11
(v3) and 7/8 (v4) with BM25-only entry search.

Signed-off-by: Jimmy Wesley <rededown@hotmail.com>
New section 5.4 records the 2026-09-11 replication of the navigation arm
with MiniCPM5-2B on the same forest and the same three question sets:
18/18, 11/11 and 7/8, precision 1.00 on the first two, median tokens
1,422 / 1,583 / 2,850, BM25-only entry search, one run per set. The one
miss (v4-07) is described as what it was: two correct queries, a correct
answer at step 5, and the harness's proof audit rejecting it because a
SQL result set has no sentence to quote. The harness change that made
the run possible is reported because its symptom scores exactly like a
wrong answer. Wall-clock is not reported: the model was served over the
network by a shared host.

Abstract, the 1.3 table, contribution 3, the related-work SLM paragraph,
the setup's models paragraph, the Forest Principle, limitation (iii) and
the quickstart are updated to point at 5.4. Document version 1.0.0 to
1.1.0.

Signed-off-by: Jimmy Wesley <rededown@hotmail.com>
One spec version since 0.79.0 (v0.80).

Behaviour changes worth reading before upgrading:

- Extensions (Part L). A plain pip install monkeyllm is unchanged: nothing
  is loaded until an operator installs an extension (vine ext install)
  and a forest enables it in _meta/extensions.yaml. That file is versioned
  and travels in a snapshot; validate reports an extension a forest
  expects and this deployment does not have, as a health line and never
  as an install. A declared secret may not be written there.

- An extension contributes at named seams (converters, curation, events,
  tools, routes under /v1/ext/<id>/, jobs, ranking, prompt, roles) and
  never patches. A contribution the host cannot serve is inert and
  named, never an error. Handlers marked heavy run in the extension's
  own environment and process.

- Audit rows gain via (ext:<id>), nullable. A row written before this
  version reads it as absent. principal stays whoever caused the act.

- Model roles carry a kind (chat, embed, vision, transcribe, rerank). An
  extension registers a role and is handed a bound caller, never an
  endpoint or a key; its spend is metered and capped per extension per
  forest, and exhaustion is a refusal.

- The MCP tools/list menu may carry extension tools; its visibility
  filter fails closed, so an unrecognised SDK shape yields fewer tools,
  never more.

- Station: /v1/ext routes, admin-gated; Studio gains an Extensions
  console. New environment: MONKEYLLM_EXT_HOME, MONKEYLLM_EXT_INDEX,
  MONKEYLLM_EXT_WORKER_TIMEOUT. pyproject declares an empty extensions
  extra as the name a future dependency lands under.

- The demo harness (examples/demo) accepts a model's native function-call
  syntax beside the JSON it asks for. Product behaviour is unchanged.

Signed-off-by: Jimmy Wesley <rededown@hotmail.com>
@JimmyWesley
JimmyWesley merged commit e1cf457 into main Sep 12, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
pypi — d1d6003e Deployed Sep 12, 2026 by JimmyWesley via publish #18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant