Skip to content

Releases

v8.2.0

Choose a tag to compare

@bdombro bdombro released this 05 Nov 19:09

[8.2.0] - 2026-11-05

Changed

  • MCP negotiation now includes 2025-11-25, retaining 2025-06-18, 2024-11-05, initialization, ping, and once-per-session roots discovery with its five-second fallback.
  • Optional mcpServer.validateOutputs checks typed MCP results without coercion, defaults, or key stripping. Opted-in typed results and JSON text match the advertised object-rooted schema; default string envelopes and scalar/array wrappers remain compatible. CLI and REST output validation is unchanged.
  • MCP handlers receive cooperative cancellation and opted-in progress through ctx.mcp. Cancelled queued work is skipped, active abortable children can stop, and tools remain serialized.
  • Explicit standard tool annotations are emitted without inferred safety claims. Parse/envelope/metadata failures now return recoverable protocol errors.
  • Non-serializable MCP results return tool errors without ending the session. Updated docs and npm examples for a compatible minor; the modern-only rewrite, native media, and Streamable HTTP remain deferred.

v8.1.0

Choose a tag to compare

@bdombro bdombro released this 05 Nov 17:26

[8.1.0] - 2026-11-05

Added

  • MCP stdio servers automatically select workspace cwd once after client initialization when exactly one usable local root is reported. Child CLIs inherit it without consumer changes. Unsupported, ambiguous, unusable, or failed roots retain launch cwd; unanswered client requests fall back after five seconds.
  • Separate MCP follow-up plan covering protocol compatibility, JSON-RPC validation, structured results, cancellation/progress, tool annotations, native content, and optional Streamable HTTP. Future features remain unimplemented.

Fixed

  • MCP stdin keeps reading and routes client responses independently while application requests remain serialized. Wire writes bypass tool output capture, and pending workspace discovery settles on disconnect or write failure.

v8.0.3

Choose a tag to compare

@bdombro bdombro released this 02 Nov 15:29

[8.0.3] - 2026-11-02

Added

  • mcp_resource_read MCP tool: when mcpServer.resources is non-empty, tools/list gains a tool that returns any resource body by URI (uri is an enum of the registered URIs), so hosts that only expose tools to the model (e.g. Copilot) can still read resources. initialize.instructions gets a one-line pointer to it when instructions are set, and .mcpb manifests list it. A command that already maps to mcp_resource_read keeps the name and the built-in is skipped.

Changed

  • agent-plugin template: just release no longer asks for confirmation and has no --dry-run; it tests, bumps, builds, commits all changes, tags, pushes and creates the GitHub release in one go.
  • Templates (api, agent-plugin) define each command's Zod schemas at the top of its command.ts instead of a per-command types.ts; docs and template AGENTS.md now recommend a sibling schemas.ts only when a schema is shared or large.

v8.0.2

Choose a tag to compare

@bdombro bdombro released this 30 Sep 20:32

[8.0.2] - 2026-09-30

Removed (breaking)

  • The not_ready InvokeFailureKind is gone (nothing produced it once the config readiness checks were removed), and OpenAPI no longer lists a 503 response on user routes. /health/readiness still answers 503.
  • App settings are no longer argsbarg's concern. appConfig (config file, env bindings, precedence, setup wizard) and the configure built-in (configure, get, set, install, uninstall, status) are removed, along with ctx.appConfig, App.appConfig, App.exportAppConfigSchema(), appConfig on InvokeHookContext / ReadinessContext, and the missing_config failure kind. Setting appConfig or configure on the app root now fails at startup with a pointer here. Migration: keep settings in app code (env vars, or your own JSON file) and add your own command if users edit them. configure is an ordinary command name again.
  • No MCP or skill install. argsbarg no longer writes ~/.agents/mcp.json or Codex / OpenCode / OpenClaw configs, and no longer detects or cleans up ~/.agents/skills/<app>/. Agent plugins and .mcpb bundles (mcp bundle) are the supported MCP install path; docs mcp now generates plugin and manual client setup (Cursor, Claude Code, Claude Desktop, Codex, OpenCode). Plugin and bundle manifests no longer carry userConfig / variables / env mappings derived from appConfig.
  • No docs built-in or docgen. The docs command and config (docs.topics, docs.enabled), the generated cli / cli-schema / mcp / http / openapi docs and --save, the <key>://docs/<topic> and <key>://schema MCP resources, and mcpServer.schemaResourceUri are removed; setting docs on the app root fails at startup. OpenAPI is still served at GET /openapi.json and /swagger, and generateOpenApi / schemaJson remain library helpers. docs is an ordinary command name again. Removed exports: DocsConfig, DocsTopic, defaultDocsTopicResourceUri, resolveDocsTopicResourceUri.
  • No generated agent skill. mcp bundle plugins ship the repository skill (skills/<key>/ or mcpServer.bundle.skillsDir) when present and no skill otherwise; the generated MCP pointer-skill fallback is gone.
  • No managed AGENTS.md. scripts/merge-agents-md.ts and the <!-- argsbarg:managed --> markers are removed; template AGENTS.md files are plain starting points that projects own. The consumers-* justfile recipes are removed.
  • No self-update or binary placement (configure install --update, Homebrew/~/.local/bin detection). Update through the package manager (brew upgrade, npm).
  • GET /health/readiness reports only the custom check (config_file and config_required are gone).
  • A relative log.file resolves against the working directory instead of the app config directory.
  • YAML input is gone. Document-mode arguments, document stdin, and HTTP request bodies accept JSON only (invalid JSON / Invalid JSON body otherwise). The YAML-style schema sections in help are unchanged.
  • OptionKind, ValueFormat, FallbackMode, and ParseKind are as const objects plus same-named union types, not TypeScript enums (so argsbarg runs under Node type stripping). OptionKind.String etc. still work and the values are unchanged; code that used them as types (kind: OptionKind.Presence in a type position) needs typeof OptionKind.Presence.
  • The package no longer ships src/ or the bun export condition. Every runtime, Bun included, loads the compiled dist/. Types are tsc-emitted dist/**/*.d.ts (with declaration maps) instead of a bundled root index.d.ts; dts-bundle-generator is gone, and argsbarg and all four templates use TypeScript 7.
  • argsbarg create: --class-name, --tap, and --homepage are removed. The identity file moved to src/create-identity.ts and holds key, releaseRepo, desc, and template; the Homebrew template derives the formula class and homepage itself.
  • Removed exports: userHome, displayAppConfigPath, resolveAppConfigPath, AnyAppConfigSnapshot, ResolvedConfig, AppConfig, AppConfigEntry, AppConfigResolveContext, AppConfigResolveFn, ConfigureConfig, ConfigureHookContext, ConfigureTargets, InstallTargetSpec, ResolvedInstallTarget.

Added

  • npm templates. cli (the default), api, and agent-plugin are npm projects: npx <key>/npm install -g, justfile tasks, tsc build, node --test, a gated just release → npm publish, and docs read from the package at runtime. api uses node:sqlite. create runs npm install/npm test for them. agent-plugin bundles with esbuild and gains a CHANGELOG and a release confirmation prompt.
  • homebrew template: a minimal Bun-compiled binary with a Homebrew formula, tap, and gated GitHub release. It is the only template that uses Bun.
  • Runs on Node ≥ 20 as well as Bun. The package ships compiled JS in dist/, which every runtime loads, and the argsbarg bin is a Node script (dist/cli-tool/main.js). The HTTP server uses node:http; stdin and subprocesses use node: APIs. See "Runtime" in docs/decisions.md.

Fixed

  • HTTP and MCP servers now honor log.enrich and log.serialize (the serve config dropped them, so only direct LogEmitter use applied them), and a log.file starting with ~/ expands to the home directory instead of creating a literal ~ directory.
  • cli.completions (enabled: false / hidden: true) now removes a command from bash, zsh, and fish completions; it was declared but never read.
  • With httpServer, mcpServer, or completion off, a root command of that name is an ordinary app command, as documented: it runs (with hooks) instead of failing with "not available for this app". Apps without such a command still get that message.
  • app.run() now runs app hooks for user commands on the CLI (beforeInvoke, afterInvoke, and formatError/onError on failure), matching app.invoke() on HTTP/MCP. Previously run() skipped them, so beforeInvoke-attached state (e.g. the template DB) was missing on the CLI.

Changed

  • Internal source reorganized after the removals: help.ts and invoke hooks live under src/runtime/, completion scripts under src/builtins/completion/, and MCP plugin/bundle packing under src/mcp/pack/. The hook skip-list no longer treats configure/docs as built-ins, so hooks now run for app commands with those names. The argsbarg bin (src/cli-tool/) uses only the public API; the template capability test moved to src/runtime/. Unused internals were deleted (runCreateCommand, parseCreateArgv, templateDir, ecsLevel, CliPresentationNode). Public exports are unchanged.
  • Help is plain text on every output: no box borders and no color; sections start with a ── Title ─── rule sized to the terminal (80 columns when piped). TTY and piped help are identical except that schema sections show by default only when piped.
  • completion <shell> --help gives generic setup instructions (current session and shell rc) instead of Homebrew-specific notes.
  • Error messages on stderr are no longer colored red.
  • The top-level examples/*.ts scripts are now type-checked with argsbarg (Node types only, so Bun APIs fail) (examples/nested.ts used Bun.file; it now uses node:fs/promises).

v8.0.1

Choose a tag to compare

@bdombro bdombro released this 30 Sep 13:29

[8.0.1] - 2026-09-30

v8.0.0

Choose a tag to compare

@bdombro bdombro released this 30 Sep 13:10

[8.0.0] - 2026-09-30

Changed (breaking)

  • New naming: an app is built with argsbarg({ … }) from a spec of commands, and the Cli prefix is gone. argsbarg({ … }) validates the spec and returns the app (export const app = argsbarg({ … }) in src/app.ts, then await app.run()); App is exported as a type only. Commands either run (handler) or group subcommands (commands), and both are declared with command({ … }). The definition is the spec: app.spec, ctx.spec, and spec on hook/runtime contexts; spec helpers (generateOpenApi, schemaStrictnessWarnings, mcpSizeReport, packMcpBundle, …) take app.spec. Public types drop Cli because argsbarg serves HTTP and MCP too; it stays only where it means the CLI surface (CliExposureConfig, cliErrWithHelp, the "cli" invocation). Key renames:

    7.x 8.0
    const program = { … } satisfies CliProgram; new Cli(program).run() export const app = argsbarg({ … }); await app.run()
    src/program.ts src/app.ts
    cli.program / ctx.program / hook ctx.program app.spec / ctx.spec / hook ctx.spec
    CliProgram / CliProgramHooks AppSpec / AppHooks
    { … } satisfies CliLeaf / CliRouter command({ … })
    CliNode / CliLeaf / CliRouter Command / RunnableCommand / CommandGroup
    CliOption / CliPositional / CliContext CommandOption / CommandPositional / CommandContext
    CliOptionKind / CliValueFormat / CliFallbackMode OptionKind / ValueFormat / FallbackMode
    CliSchemaValidationError / LeafInputError / CliJsonSchema / CliLeafInputs SchemaValidationError / InputError / JsonSchema / CommandInputs
    CliAppConfig / CliLocals / CliInvocation AppConfig / Locals / Invocation
    CliMcpServerConfig / CliHttpServerConfig / CliDocsConfig … McpServerConfig / HttpServerConfig / DocsConfig …
    CliCliExposureConfig CliExposureConfig
    isDocumentLeaf / buildLeafInputSchema / leafWireOptions isDocumentCommand / buildCommandInputSchema / commandWireOptions
    cliSchemaExport / cliSchemaJson schemaExport / schemaJson

    Validation now happens when argsbarg() runs (at import of src/app.ts). The docs name the app's own config schema Settings so it doesn't clash with argsbarg's AppConfig type. declare module "argsbarg" augmentations use Locals / ServerState. User-facing messages say "command" / "command group" / "app root" instead of leaf / router / program root.

  • Schemas are authored in Zod 4 (zod is now a peer dependency). inputSchema, outputSchema, httpServer.errors.errorSchema, and mcpServer.errors.errorSchema take Zod schemas; argsbarg validates with Zod and emits JSON Schema (draft 2020-12) for MCP tools/list, OpenAPI, non-TTY help, and docs cli-schema. Passing a JSON Schema object fails at startup with a migration error.

  • program.appConfig.jsonSchema is replaced by program.appConfig.schema, which takes a Zod object schema (z.strictObject recommended). Without it, argsbarg still synthesizes an all-string schema from entries.

  • ctx.inputs for a leaf with inputSchema is now the schema's parsed output: defaults and transforms are applied, and strict schemas reject unknown keys as before.

  • Schema validation errors are Zod's messages prefixed by path, polished for agents: missing fields read name: required, unknown keys list what is allowed ($: Unrecognized key: "titel" (allowed: action, doc, title)), and union/enum mismatches echo the rejected value (steps.0.kind: Invalid discriminator value. Expected 'alpha' | 'beta' (got "alfa")). This replaces argsbarg's union-narrowing rewrites.

  • Partial config validation (configure set, bootstrap) makes top-level keys optional via .partial(); nested required fields are no longer relaxed.

Removed (breaking)

  • argsbarg schemagen, the /** @sg */ markers, and __generated__/ artifacts: define schemas in Zod instead. The ts-json-schema-generator and @cfworker/json-schema dependencies are gone (argsbarg has no runtime dependencies; zod is the only peer).
  • Subpath exports argsbarg/cli, argsbarg/headless, argsbarg/http, argsbarg/mcp, and argsbarg/schemagen: import from "argsbarg" (everything they exported is on the root).
  • JSON Schema draft selection via $schema (argsbarg emits draft 2020-12) and the comma-list JSON Schema format registration.
  • The consumers-schemagen recipe; sqsp-i18n-tools-poc is no longer a tracked consumer. consumers-dev now forces the install, adds zod, and removes the nested dev copy of zod; the new examples-install recipe reinstalls the in-repo examples.
  • ctx.inputsAs<T>(): use ctx.inputs with command.
  • The CliHandler type export (unused since handlers are typed through command / program).
  • kind: "json" leaves, isJsonLeaf, and JSON_LEAF_BODY_KEY: use kind: "document", isDocumentCommand, and DOCUMENT_LEAF_BODY_KEY. kind: "json" now fails at startup with a migration error.
  • CliSkillConfig / program.skill (it had no effect since skill generation was removed).
  • The dedicated startup errors for long-removed configure settings (prefix, agentIntegration, and per-host skill/MCP targets). Unknown target keys still fail with configure.targets.<key> is not a valid target key.

Migration (7 → 8)

  1. Add zod@^4 to your dependencies.
  2. Convert each /** @sg */ type to export const X = z.strictObject({…}) plus export type X = z.infer<typeof X>, copying every JSDoc into .describe("…"). Agents read these descriptions, and Zod does not read JSDoc.
  3. Pass the Zod schemas to inputSchema / outputSchema / errorSchema, rename appConfig.jsonSchema → appConfig.schema, build the app with export const app = argsbarg({…}) in src/app.ts (await app.run() in index.ts), wrap every command in command({…}), use ctx.spec / app.spec where you used ctx.program / cli.program, replace ctx.inputsAs<T>() with ctx.inputs (path params: ctx.pathParams), change kind: "json" to kind: "document", and drop skill: { … }.
  4. Replace subpath imports with "argsbarg", delete __generated__/, and remove the schemagen recipes and gitignore rules.
  5. Diff docs cli-schema output before and after to confirm every description survived. See docs/developing.md → "Upgrading consumer apps to 8.0".

Added

  • command() infers ctx.inputs from inputSchema and types the handler return from outputSchema. It is now the way to declare leaves; { … } satisfies RunnableCommand is no longer documented or used in the templates (it still compiles, but its handler gets untyped ctx.inputs).
  • program() declares the program root: router roots keep their literal type, and a leaf root (one-command CLI) gets the same ctx.inputs inference as command. It replaces satisfies Program in the docs and templates.
  • command() also types ctx.inputs for leaves without an inputSchema, from their own options / positionals literals: presence flags are boolean, numbers number, enums their choices union, durations number (ms), comma-lists string[], and required or defaulted options are non-optional. Types only; runtime parsing is unchanged. CommandBase.options, positionals, and CommandOption.choices accept readonly arrays.
  • Leaves can declare pathParams: z.strictObject({ id: z.string().describe(…) }) for the :param segments above them: values are validated before the handler, typed as ctx.pathParams with command, and described in MCP tool schemas and OpenAPI path parameters. Startup checks that the keys match the route and are not also declared by inputSchema. The raw segments stay available as ctx.rawPathParams.
  • Startup validation emits every schema eagerly, so schemas JSON Schema cannot represent (transforms, z.date(), …) fail at startup with the leaf named.
  • schemaStrictnessWarnings(program) (exported) lists input and config objects that accept unknown keys (z.object instead of z.strictObject). The schema templates assert it is empty in src/program.test.ts, and MCP and HTTP servers log each warning at startup (schema.strictness).
  • JSON Schema authoring guide rewritten for Zod (docs/json-schema-subset.md), and ADR 4 (Zod as the schema layer) supersedes ADR 2.
  • The root export now includes every public type that was previously only reachable through the bundled index.d.ts (RunnableCommand, CommandGroup, Command, JsonSchema, …), plus the HTTP server and Claude/Cursor plugin helpers.

Fixed

  • PUT / PATCH on :param routes (e.g. /workspaces/:id) no longer fail with unknown property "id" when the leaf's inputSchema is strict: path parameters the schema does not declare are left out of validation and merged into ctx.inputs (also available as ctx.pathParams).
  • MCP tools under :param routers (e.g. workspaces :id get) now list each path parameter as a required argument and route calls to the given value. Previously their input schemas omitted the parameter and calls routed the literal :id segment, so agents could not address these routes.
  • Document leaves under :param routes accept HTTP and MCP calls whose body carries the path parameters (they are validated as path parameters, not body fields).
  • OpenAPI request and response schemas no longer embed a root $schema.
  • Copy templates are renamed and keyed by their directory: examples/cli (default; was full-example), examples/api (was full-example-json), and examples/agent-plugin (was mcp-plugin). argsbarg create --template cli|api|agent-plugin (was cli / json / plugin); create-identity.ts stores the same key. The example apps inside are example-cli, example-api, and example-agent-plugin. The interactive picker now lists every template (it only offered two), and `create --chec...
Read more

v7.1.4

Choose a tag to compare

@bdombro bdombro released this 30 Sep 08:29

[7.1.4] - 2026-09-30

Changed

  • The MCP plugin example now ships a committed, self-contained Node bundle (dist/mcp-plugin.mjs) that both plugin manifests run with node, replacing source-only bun start. Plugin users need Node >=20 instead of Bun, and startup installs nothing. just check rebuilds the bundle, the release script rebuilds it after the version bump, and the optional docs/node-distro.md guide is removed.

v7.1.3

Choose a tag to compare

@bdombro bdombro released this 29 Sep 10:39

[7.1.3] - 2026-09-29

Added

  • MCP tools whose inputSchema or outputSchema root is not type: "object" (e.g. a discriminated-union anyOf from export type Input = A | B) are now wrapped for MCP as { input: <schema> } / { result: <schema> }, with definitions moved to the new root. MCP requires an object root, and the TypeScript SDK rejects anything else; previously these tools shipped schemas clients refused or showed no fields for. tools/call unwraps input before invoke (handlers and inputSchema validation still see the exact union) and wraps structuredContent under result to match. CLI and HTTP are unchanged. See docs/mcp.md.
  • Startup validation (MCP enabled only): every exposed MCP tool's served schemas must have resolvable local $refs, and wrapped schemas must not use $ref: "#".
  • full-example-json gains a shape-area union-input leaf demonstrating the MCP wrap.
  • argsbarg create drops template lines marked # argsbarg-dev-only from new projects. The in-repo examples use it for the just setup step that repairs node_modules/.bin/argsbarg for file:../.. installs (now in all three templates); scaffolded projects never see it.

Changed

  • Docs now use bun x instead of bunx, and create examples use bun x argsbarg@latest create so scaffolding never runs a stale cached argsbarg (old templates, old ^ version in package.json). create --check examples keep bun x argsbarg so they check against the project's installed version.
  • The MCP plugin example now defaults to source-only Bun startup with inline Claude and Cursor MCP configuration, updated plugin recipes, unit/integration/agent-E2E guidance, and an optional Node distribution guide.

Fixed

  • schemagen now hoists a root $ref (from export type Input = Inner, generic aliases like Box<string>, or alias chains) to the object definition it names. Previously these roots had no type: "object" or properties, so MCP rejected the tool schema, --help showed no input rows, and Json-option/properties checks were skipped.
  • schemagen no longer adds additionalProperties: false to non-object roots. On a union root it rejected every property, so union-typed inputs never validated.
  • JSON Pointer $ref resolution (discriminated-union error reporting, OpenAPI dereferencing) now decodes percent-escaped segments such as #/definitions/Box%3Cstring%3E.
  • The full-example and full-example-json justfiles derive tap_parent/tap_path from a literal tap := "org/repo" instead of raw {tapOrg}/{tapRepo} placeholders, which only create filled in. Run in-repo, the Homebrew recipes targeted Taps/{tapOrg}/homebrew-{tapRepo}, and create --check reported drift. A new test runs create --check on every in-repo template as part of just test.
  • The MCP plugin example's release --dry-run now prints the planned actions without running checks, changing files, or publishing.

v7.1.2

Choose a tag to compare

@bdombro bdombro released this 25 Sep 06:59

[7.1.2] - 2026-09-25

Added

  • mcpServer.instructions — an optional string returned as initialize.result.instructions. Claude Code adds it to the system prompt of every session; Cursor writes it to mcps/<server>/INSTRUCTIONS.md.
  • MCP protocol version negotiation: initialize now echoes a client's 2025-06-18 or 2024-11-05 protocolVersion, and answers 2025-06-18 (the newest) when the request omits it or asks for an unsupported version. Previously the server always claimed 2024-11-05 regardless of what the client sent or what fields it actually returned. tools/list's outputSchema and tools/call's structuredContent — both defined starting in 2025-06-18 — are now only sent for sessions that negotiated that version or later; a 2024-11-05 session no longer receives fields from a spec revision it never agreed to.
  • mcpSizeReport(root) and mcpServer.sizeLimits — measures every MCP tool's description length and pretty-printed definition (bytes and lines) against configurable limits approximating two real client behaviors (Claude Code truncates long tool descriptions; Cursor reads each tool's synced definition file in bounded chunks), and returns warnings for anything over. serveMcp runs this at startup and writes warnings to stderr before the "MCP ready" line; docs mcp now includes a ## Tool sizes table. Set any limit to false to disable that check.
  • mcpTool.notes (string | false) — overrides a leaf's notes in the MCP tool description only; CLI --help continues to show the leaf's own notes unchanged. Useful for a note that only makes sense with --help in front of it, or to keep a tool's definition under a size limit.

Changed

  • Discriminated anyOf/oneOf unions (every branch has a properties key with a string const or all-string enum, and the value sets are disjoint) now report only the branch matching the instance's discriminator value, instead of every branch's unrelated errors at once. A missing, non-string, or unmapped discriminator value collapses to one synthetic message naming the valid choices. Non-discriminated unions are unaffected. Along the way, two cfworker @cfworker/json-schema quirks are also cleaned up for every validated schema (not just discriminated unions): a spurious additionalProperties + "False boolean schema." pair it emits even for a property that's genuinely declared in properties, and dropping now-redundant wrapper errors ($ref, properties, items, anyOf, oneOf, …) once a more specific error survives underneath them. Discriminator detection also resolves each branch through $ref before inspecting its properties — schema generators such as ts-json-schema-generator write every anyOf branch as a bare { $ref } into definitions rather than inlining it, which previously made every branch look property-less and silently fell back to the noisy full-error listing.

v7.1.1

Choose a tag to compare

@bdombro bdombro released this 25 Sep 02:59

[7.1.1] - 2026-09-25

Added

  • argsbarg create --template plugin — support "plugin" choice for scaffolding agent MCP plugins with in-repo Cursor and Claude manifests.

Changed

  • AGENTS.md — updated Memory section to use thread-memory MCP plugin (recall/feedback) backed by centralized SQLite store.

Fixed

  • Headless tool failures (MCP tools/call and HTTP JSON { "error" }) now return the full error message (ANSI stripped, newlines preserved) instead of collapsing to the first line.
  • packClaudePlugin, packCursorPlugin, and packMcpBundle staged the compiled binary via cpSync(src, dest, { mode: 0o755 }) — but cpSync's mode option is a bitmask of copy-behavior flags (COPYFILE_EXCL/FICLONE/FICLONE_FORCE, valid range 0–7), not a POSIX file permission mode. 0o755 (493) was always out of range; a stricter Bun fs.cpSync validation now throws on it instead of silently ignoring it. Fixed by dropping the bogus mode option and calling chmodSync(dest, 0o755) after the copy, which is what the code actually intended.