Smithers is incur's most demanding consumer — every one of its 59 CLI commands is built on incur. Reading the actual integration code (apps/cli/src/index.js), there are documented "Findings" where Smithers works around incur limitations. These translate directly into features.
Smithers has elaborate workaround code for Finding #1: incur hardcodes exit code 4 for validation errors, but Smithers devtools commands need exit code 1. Smithers pre-validates argv before incur sees it and remaps exit codes after cli.serve() returns. Incur should let commands declare their own exit code table:
command('tree', {
exitCodes: { validation: 1, notFound: 4 },
// ...
})Finding #2: Some commands (agents capabilities, agents doctor) own stdout completely and emit raw JSON. Smithers intercepts argv before incur runs via runRawJsonAgentCommandIfMatched() and calls process.exit(0) directly — completely bypassing incur. Incur should support:
command('capabilities', {
outputPolicy: 'raw', // no envelope, no CTAs
})Finding #3: --json collides — incur treats it as --format json, but Smithers devtools commands use --json as a boolean "emit JSON tree" option. Smithers rewrites argv (--json → -j) before incur parses it. Incur should let commands reserve or shadow global flags:
command('tree', {
shadowGlobals: ['json'], // --json is mine, not --format json
options: z.object({ json: z.boolean() }),
})Line 5680: "Incur does not call the exit callback on success paths." Smithers has to check commandExitOverride separately after serve() returns. This should just work — call the exit callback with code 0 on success too.
Smithers rewrites smithers workflow.tsx → smithers up workflow.tsx by detecting .tsx extensions before incur parses. Incur could support declarative file routing:
cli.fileRoute({ pattern: /\.tsx$/, command: 'up' })Smithers has 5 separate rewriteXxxArgv() functions that transform argv before cli.serve(). Incur should support a pre-parse hook:
cli.beforeParse((argv) => {
// transform, rewrite, validate
return argv
})Commands like logs --follow and tree --watch manually set up AbortController, SIGINT/SIGTERM handlers, and cleanup. Incur could provide:
command('logs', {
streaming: true,
async *run(c) {
// c.signal is an AbortSignal wired to SIGINT/SIGTERM
// cleanup runs automatically on abort
for await (const event of stream) {
if (c.signal.aborted) break
yield event
}
}
})Smithers maintains two separate MCP servers: one "raw" (1:1 CLI→tool mapping via incur) and one "semantic" (hand-crafted tool names/descriptions for better agent UX). Incur could support MCP tool transformers:
cli.mcp({
surface: 'semantic',
transform: (tool) => ({
name: `smithers_${tool.name}`,
description: rewriteForAgents(tool.description),
})
})Smithers has approval gates (<Approval>, <HumanTask>) that need human input. Incur could add structured prompt primitives that render as interactive TUI for humans and structured JSON requests for agents:
const decision = await c.prompt.select({
message: 'Approve this task?',
choices: ['approve', 'deny', 'skip'],
})Smithers exposes an HTTP server (up --serve --port 7331). For real-time workflow monitoring, incur's cli.fetch handler could support Server-Sent Events or WebSocket subscriptions alongside request/response.
Smithers has .smithers/workflows/ where users add custom workflows. These could auto-contribute CLI commands. Incur could support lazy command registration from external packages:
cli.plugin('./workflows/', {
pattern: '*.tsx',
mount: (file) => command(file.name, { /* ... */ })
})Smithers already uses .smithers/smithers.config.ts. Incur's config system only supports JSON loaders. Since incur runs on Bun, it could natively support .ts config files.
smithers up --detach forks a background process. Incur could provide built-in daemon primitives: PID file management, start/stop/status lifecycle, and log file routing — since this is a common pattern for CLI tools that manage long-running processes.
The highest-ROI features are 1-4 — they eliminate actual workaround code in Smithers today (roughly 200 lines of argv rewriting, exit code remapping, and pre-incur interception). Features 5-8 replace repeated boilerplate patterns. Features 9-13 are strategic bets that align incur with orchestrator/daemon use cases where the CLI is a control plane, not a one-shot tool.