Glove 3.0.0 lands four big shifts: first-class subagents with a factory pattern, a guaranteed-symmetric event system for hooks/skills/subagents, sub-stores for per-run cost attribution, and a default MemoryStore in glove-core so a fresh Glove works without any store wiring.
Alongside core, four packages ship at 0.5.0 as early-access: glove-mcp, glovebox-core, glovebox-kit, glovebox-client.
defineSubAgent takes a factory that returns a fully-built child Glove. The framework runs child.processRequest(prompt, signal) and returns the final agent text as the tool result.parentStore.createSubAgentStore(name, durable?) spins up an isolated child store so subagent conversations and token usage are tracked independently. Implemented by the new MemoryStore; opt-in for custom stores.subagent_invoked / subagent_completed are fired by the Executor (not the dispatcher), so the bracket closes even when an abort short-circuits the dispatcher's promise. Subscribers see 1:1 pairs.Glove instantiates a MemoryStore automatically when no store is supplied.ESCAPE_COMPACTION_THRESHOLD (default 90%) prevents tool_use / tool_result pairs from being split across compaction boundaries.| Package | Version |
|---|---|
glove-core | 3.0.0 |
glove-react | 3.0.0 |
glove-voice | 3.0.0 |
glove-next | 3.0.0 |
Four packages ship as 0.5.0. They're production-grade but the surface is still solidifying — semver-minor bumps may land in 0.6.x.
| Package | What it does |
|---|---|
glove-mcp | MCP server bridging. mountMcp reloads previously-activated servers and registers the discovermcp discovery subagent. Promoted from internal use to a stable surface. MCP guide → |
glovebox-core | Authoring kit and glovebox build CLI. Wrap a built Glove runnable, run glovebox build, ship the resulting Dockerfile or nixpacks bundle to any container host. Glovebox guide → |
glovebox-kit | In-container runtime. Hosts a Glove agent behind a single authenticated WebSocket plus an HTTP /files route for outputs. Most consumers don't import this directly — glovebox build generates a server entry that uses it. |
glovebox-client | Client SDK for talking to a deployed Glovebox server. One WebSocket per session, multiple prompts multiplexed. Streams subscriber events and display slot pushes; resolves with the final assistant message and an outputs map of FileRefs. |
glove-sqlite is deprecated and will not receive new features. The new MemoryStore in glove-core covers most prototyping needs; for production durability, BYO StoreAdapter. The package still installs and works, just without createSubAgentStore support.
StoreAdapter.addTokens(args: TokenConsumptionCounter)Was (count: number). The counter is { tokens_in: number; tokens_out: number } — the framework now records both directions separately, useful for per-direction cost reporting. getTokenCount() still returns a single sum. Affects every custom StoreAdapter.
// Before
async addTokens(count: number) {
this.tokens += count
}
// After
async addTokens(args: TokenConsumptionCounter) {
this.tokens += args.tokens_in + args.tokens_out
}In glove-react, the same change applies to RemoteStoreActions.addTokens(sessionId, args: TokenConsumptionCounter) — breaking for any consumer wiring custom remote-store actions.
defineMention → defineSubAgent (factory pattern)defineMention(args) is removed. The whole Mention* family of types is replaced by SubAgent*. The shape changed too: instead of returning string content, the factory builds and returns a fully-built child Glove. The framework calls child.processRequest(prompt, signal) and uses the final agent text as the tool result.
// Before
glove.defineMention({
name: "researcher",
handler: async ({ prompt, controls }) => {
return "research result"
},
})
// After
import { Glove, MemoryStore } from "glove-core"
glove.defineSubAgent({
name: "researcher",
description: "Deep web research subagent",
factory: async ({ parentStore, parentControls, prompt, name }) => {
const subStore = await parentStore.createSubAgentStore?.(name, false)
?? new MemoryStore(`${name}_${Date.now()}`)
return new Glove({
store: subStore,
model: parentControls.glove.model,
displayManager: parentControls.displayManager,
systemPrompt: "You are a researcher.",
compaction_config: {
compaction_instructions: "Summarize research progress.",
},
})
.fold(searchTool)
.fold(fetchTool)
.build()
},
})The agent invokes the subagent through the auto-registered glove_invoke_subagent tool — the user's @subagent-name text in messages still reaches the model verbatim as a routing nudge.
glove-mcp: discoveryTool → discoverySubAgent; find_capability → discovermcpdiscoveryTool({...}) is renamed discoverySubAgent({...}) and now returns DefineSubAgentArgs (used with glove.defineSubAgent(...) instead of glove.fold(...)). The discovery subagent's name is discovermcp (was find_capability); the model invokes via glove_invoke_subagent({ name: "discovermcp", prompt: "..." }).
mountMcp consumers don't need to change anything — it wires the new shape internally. Update any system prompt that mentions the old name:
// Before
systemPrompt:
"When the user asks for an external integration, " +
"call find_capability to discover and activate the right MCP server."
// After
systemPrompt:
"When the user asks for an external integration, " +
"invoke the `discovermcp` subagent (via the `glove_invoke_subagent` tool) " +
"with a brief description of what you need."User text containing /skill-name or /hook-name directives is no longer stripped from the persisted user message. Each bound directive is replaced by a non-triggerable placeholder of the form [invoked_extension__hook_<name>] or [invoked_extension__skill_<name>]. Hook and skill handlers receive parsedText containing the placeholder, not the bare directive.
UIs that previously rendered raw user text now see the placeholder embedded in the message body. If you need the original text (e.g. for a hook that rewrites the message), read the new Message.pre_modified_text field.
Tool.run and GloveFoldArgs.do gain optional signalTool.run(input, handOver?, signal?) — backward-compatible; tools that ignore the third arg still work. GloveFoldArgs.do(input, display, glove, signal?) similarly gains an optional fourth signal. Tools that perform long-running internal work (subagent dispatchers, fetches) should forward it so abort propagates all the way down.
Five new SubscriberEvent variants:
token_consumption — { consumption: TokenConsumptionCounter }. Fired by the Observer after each model turn.hook_invoked — { name }. Fired by Glove just before a hook handler runs.skill_invoked — { name, source: "user" | "agent", args? }. User-side fires from Glove; agent-side fires from the skill dispatch tool.subagent_invoked — { name, prompt }. Fired by the Executor before invoking the subagent dispatch tool.subagent_completed — { name, status: "success" | "error", message? }. Fired by the Executor after the dispatch tool resolves OR on abort.Bracket symmetry is guaranteed. The Executor brackets every glove_invoke_subagent call regardless of outcome, so a parent-side abort that cuts the dispatcher's promise still produces a matching close bracket. Subscribers can model subagent runs as a stack and trust the brackets.
StoreAdapter.createSubAgentStore?(namespace, durable?) is a new optional hook. With durable: false (default) it returns a fresh child store per call; with durable: true it returns a cached child for the namespace, so a subagent can carry message history across invocations.
The new MemoryStore in glove-core implements this out of the box, so subagents derived via the standard factory pattern get isolated child stores automatically.
MemoryStore in glove-coreA comprehensive in-memory StoreAdapter is now exported from glove-core. It implements the full surface (messages, tokens, turns, tasks, permissions, inbox, sub-stores) and is used as the default when Glove is constructed without a store.
import { Glove, MemoryStore, Displaymanager, createAdapter } from "glove-core"
const agent = new Glove({
store: new MemoryStore("session"), // optional — default is a fresh MemoryStore
model: createAdapter({ provider: "anthropic" }),
displayManager: new Displaymanager(),
systemPrompt: "You are a helpful assistant.",
compaction_config: { compaction_instructions: "Summarize so far." },
}).build()AgentControls exposes the parent's displayManager directly so subagent factories can build a child Glove that pushes UI to the parent's display stack. New setDisplayManager(dm) on IGloveRunnable / IGloveBuilder lets a subagent swap displays mid-run if it changes its mind.
Glove.build(store?) and Glove.rebuild(store?)The store can now be supplied at build time instead of construction time. Tools folded before build are correctly transferred into the rebuilt executor — this is what makes the subagent factory pattern work cleanly.
Observer.ESCAPE_COMPACTION_THRESHOLD (default 90%) is a soft trigger before the hard CONTEXT_COMPACTION_LIMIT. If the soft threshold is crossed AND the model just produced tool calls, Agent.ask runs runCompactionNow() before appending the tool calls — keeping tool_use and matching tool_result pairs together post-summary. Configurable via the Observer constructor's 7th arg.
Message.pre_modified_textWhen a hook rewrites a user message via HookResult.rewriteText, the original text is now preserved on the new pre_modified_text field of the message — so UIs can still display what the user actually typed.
StoreAdapter to the new addTokens(args: TokenConsumptionCounter) signature. If you maintain a single sum, add args.tokens_in + args.tokens_out.RemoteStoreActions.addTokens for glove-react, update its signature too.defineMention call with defineSubAgent + a factory that returns a built IGloveRunnable. Remove imports of MentionContext, MentionHandler, MentionOptions, DefineMentionArgs, RegisteredMention.discoveryTool directly (rather than going through mountMcp), rename to discoverySubAgent and pass it to glove.defineSubAgent(...).find_capability — point at discovermcp via the glove_invoke_subagent dispatch tool instead.[invoked_extension__<type>_<name>] placeholders. If you need the unmodified text after a hook rewrite, read Message.pre_modified_text.StoreAdapter.createSubAgentStore on your custom store so subagents get isolated child stores for cost attribution. Stores that don't implement it still work — the dispatcher falls back to whatever the factory builds.signal from Tool.run / GloveFoldArgs.do into any long-running internal work in your tools (network fetches, nested agent loops). Tools that ignore signal still get the executor's abortable-promise unwind for free.glove-sqlite, plan a migration to a custom StoreAdapter backed by your production database. glove-sqlite still works but is no longer maintained. glove-core.Glove agents.