Feature Description
Disclaimer: This message was synthesized by an AI from a long, unstructured Markdown file of notes accumulated while building real mods. Use cases have been kept intentionally simple and generic. If anything seems off or incoherent, feel free to ask for clarification — the AI may have misread some details.
Part 1 — UI / Design (high priority)
These are foundational. Better UI primitives make every other mod feature more useful. That's why they come first.
1. cmd.ui.panel() / cmd.ui.divider() — native layout helpers
Problem: Every mod that wants to display a panel or separator has to rewrite the same ~50 lines of utilities (terminal width handling, ANSI, padding). There's no visual consistency across community mods.
Use case: Any mod that displays structured output in the feed currently duplicates the same layout boilerplate. A shared cmd.ui.panel(['line 1'], { title: 'my-mod' }) and cmd.ui.divider() would give all mods a consistent look for free.
2. cmd.ui.spinner() — native spinners
Problem: There's no way to show a loading indicator during async work. Packages like ora don't work inside the harness sandbox.
Use case: A mod that does any async operation at startup (network call, file scan, etc.) has no way to tell the user it's working. A native spinner would be the most basic UX expectation.
const spinner = cmd.ui.spinner("Loading...");
await task();
spinner.success("Done!");
3. cmd.ui.table() — structured data display
Problem: Displaying a formatted table requires manual .padEnd() per column, which breaks as soon as data changes or the terminal is too narrow.
Use case: Any mod that shows structured data with multiple columns (name, value, status, etc.) would benefit from a standard table primitive rather than fragile manual padding.
cmd.ui.table({
headers: ['Name', 'Value', 'Status'],
rows: [['item-1', '42', 'ok']],
align: ['left', 'right', 'left'],
});
4. Structured cmd.ui.setStatus() with colored badges (footer)
Problem: setStatus() only supports plain text in the footer. No color, no icon, no badge styling.
Use case: A mod that tracks some state would benefit from being able to show a colored, iconified badge in the footer (● active in green, a counter in yellow) rather than unformatted text.
cmd.ui.setStatus([
{ text: 'active', color: 'green', icon: '●' },
{ text: '14 items', color: 'yellow', icon: '📦' },
]);
5. cmd.ui.widget() — actually wired in the TUI
Problem: cmd.ui.widget() exists in the API and is used in community mods (e.g. David Thyresson's weather mod), but it's currently a no-op — the widget renders nowhere.
Use case: Any mod that wants to show persistent information above the editor (status, live counter, etc.) is currently blocked. The code exists; it just needs to be wired up in the TUI.
6. w.update() — update a widget without recreating it
Problem: To update a widget's content, you have to .dispose() it and create a new one. This causes flickering and unnecessary boilerplate.
Use case: Any widget displaying live or periodically refreshed data needs to update its content without destroying and recreating the whole component.
const w = cmd.ui.widget({ render: () => ['loading...'] });
// later:
w.update(() => [`${count} items`]);
7. ANSI / color support in dialogs (confirm, select, notify)
Problem: Dialog text in cmd.ui.confirm(), cmd.ui.select(), and cmd.ui.notify() is rendered as plain text — ANSI escape codes are not parsed.
Use case: A confirmation dialog that visually distinguishes a dangerous action (red/bold title, colored options) is much clearer than a plain-text prompt. Color in dialogs is a basic UX expectation.
8. cmd.ui.confirm() with custom button labels
Problem: cmd.ui.confirm() always shows "OK" and "Cancel". There's no way to customize the button labels.
Use case: Any confirmation that involves a specific action ("Delete", "Overwrite", "Enable") should be able to label its buttons accordingly rather than relying on the generic "OK".
cmd.ui.confirm({
title: 'Overwrite this file?',
labels: { confirm: 'Overwrite', cancel: 'Keep existing' },
});
9. cmd.ui.progress() — progress bar for long operations
Problem: There's no way to show progress during a multi-step or time-consuming operation. The user has no feedback while the mod is working.
Use case: Any mod that processes multiple items sequentially or does a long async operation should be able to show a progress bar rather than leaving the user wondering if it's stuck.
const bar = cmd.ui.progress({ total: 100, label: 'Processing...' });
bar.update(45);
bar.complete('Done!');
10. cmd.ui.menu() — interactive select with groups and search
Problem: cmd.ui.select() is basic — no groups, no filtering, no advanced keyboard navigation.
Use case: Any mod presenting a long list of options would benefit from a searchable, keyboard-navigable menu rather than a flat list the user has to scroll through.
11. cmd.ui.clearFeed() — clear the feed
Problem: There's no way to clear old messages from the feed. A mod that displays updates periodically accumulates lines that stay forever.
Use case: A mod that shows a regularly updated report should be able to clear its previous output and redisplay cleanly, rather than appending duplicate blocks on every update.
cmd.ui.clearFeed({ keepLast: 5 });
12. cmd.ui.spacing() — explicit spacing
Problem: Adding blank lines between display blocks currently requires console.log(""). This is non-standard and bypasses the API.
Use case: Any mod that displays multiple panels or sections needs a clean, idiomatic way to add vertical spacing.
cmd.ui.spacing(2); // 2 blank lines
13. Theming / shared color palette across mods
Problem: Every mod hardcodes its own colors. There's no way to share a theme across multiple mods, or to let the user customize the visual style.
Use case: An author publishing a set of related mods would want them to share a consistent visual identity without duplicating ANSI constants across every file. Users would benefit from being able to adjust colors to match their terminal theme.
14. cmd.ui.push() — more prominent push notification
Problem: cmd.ui.notify() adds a message to the feed, which gets lost in the scroll. There's no way to attract the user's attention more visibly.
Use case: A mod that needs to alert the user about something important (a threshold crossed, an error detected) should have a way to show a more prominent notification that doesn't get buried in feed history.
cmd.ui.push({ title: 'Threshold reached', body: 'The limit has been exceeded', level: 'warning' });
Part 2 — Lifecycle, Hooks & Persistence
15. cmd.globalStore — cross-session key-value store
Problem: There is no way to persist data across sessions without writing a JSON file via cmd.exec("bash -c 'cat > ...'"). This works but it's a workaround, not an API.
Use case: Any mod that wants to remember something between sessions (counters, preferences, history) currently has to manage raw files manually. A simple cmd.globalStore.set/get would be the standard path.
await cmd.globalStore.set("total-count", 42);
await cmd.globalStore.get("total-count");
16. cmd.setInterval() — periodic refresh with automatic cleanup
Problem: Mods that need periodic refresh (clock, live data, etc.) each implement their own setInterval / clearInterval tied to onSessionStart / onSessionEnd. It's identical boilerplate in every mod.
Use case: Any mod with a periodic refresh cycle should be able to register it in one line and have the cleanup handled automatically at session end, rather than reimplementing the same lifecycle pattern every time.
cmd.setInterval(() => {
cmd.ui.refreshWidgets();
}, 1000); // auto-cleaned at session end
17. cmd.setFlag() — mutable flags at runtime
Problem: Flags (cmd.addFlag) cannot be updated at runtime. If a mod exposes a configurable option via a slash command, it must use a closure variable — not a real flag.
Use case: A mod configurable via /my-mod option value should be able to update a real flag value live, so the next refresh picks it up immediately without a restart.
cmd.setFlag('mode', 'compact');
18. afterToolCall — reliable toolName and input in hook payload
Problem: The docs say afterToolCall receives {toolCallId, toolName, input, result}, but in practice toolName and input don't seem consistently present. Mods end up guessing field names (input.file_path || input.path || input.file), which is fragile.
Use case: Any mod reacting to specific tool calls needs to reliably branch on toolName and read input without heuristics. This may just be a documentation or typings issue — but it should be verified and guaranteed.
19. beforeToolBatch — view the full batch before execution
Problem: beforeToolCall fires per tool call. There's no way to analyze the full set of planned actions before any of them execute.
Use case: A safety-oriented mod that wants to warn the user when many actions are planned at once needs to see the full batch upfront — not intercept each call individually after execution has already started.
cmd.hooks({
beforeToolBatch: async ({ toolCalls }) => {
if (toolCalls.length > 5) {
const ok = await cmd.ui.confirm({ title: `${toolCalls.length} actions planned. Continue?` });
if (!ok) return { block: true };
}
}
});
20. onStop with a granular stopReason
Problem: onStop fires when the model stops, but also when an injected turn (from a stop_hook) ends. Distinguishing the two requires a custom state machine in every mod that needs it.
Use case: A mod that only wants to react to a natural end-of-run (not to injected turns) needs to be able to filter on stopReason === 'end_turn' without building a two-phase state machine.
cmd.hooks({
onStop: async ({ stopReason }) => {
if (stopReason !== 'end_turn') return;
// react only to natural run end
}
});
21. afterModelResponse — hook on the model's final text
Problem: There's no way to inspect or modify the model's response before it's shown to the user.
Use case: A mod that monitors model output for specific patterns (warnings, risky content, missing context) needs to be able to read — and optionally annotate — the response at the point where it's produced, before it reaches the feed.
cmd.hooks({
afterModelResponse: async ({ text }) => {
if (someCondition(text)) {
return { text: "⚠️ Note:\n\n" + text };
}
}
});
22. cmd.openBrowser() / cmd.openFile() — cross-platform helpers
Problem: Opening a file or URL from a mod requires cmd.exec({ command: 'open', args: [path] }), which is macOS-only and not part of the official API.
Use case: Any mod that generates output (a report, a preview, a dashboard) and wants to open it for the user should be able to do so with a cross-platform API call rather than platform-specific shell commands.
await cmd.openFile('/path/to/report.html');
await cmd.openBrowser('http://localhost:3000');
23. Programmatic sub-agents from a mod
Problem: Only the model can launch sub-agents via the agent tool. A mod has no way to orchestrate parallel workers or delegate work to a dedicated sub-agent.
Use case: A mod that needs to run background analysis or parallel processing on independent sub-tasks currently has no API path to do so — the orchestration logic has to live entirely in the model's prompt instead.
const result = await cmd.runSubagent({
model: "haiku",
prompt: "Analyze this file",
tools: ["read_file"],
timeout: 30_000,
});
Addendum - a few more gaps I forgot to include:
- cmd.getAvailableModels() — machine-readable model list
The /model command shows model names, but the display names don't match the IDs the API actually accepts. There's no way for a mod to programmatically get the list of valid model identifiers to use with cmd.setModel().
- Per-model pricing exposed to mods
No way to get input/output cost per token from within a mod. Mods that track or estimate cost have to hardcode price tables manually and keep them up to date themselves.
- cmd.usage — cumulative session/lifetime usage
The model_request_end event gives per-turn token usage, but there's no way to access cumulative usage for the current session or across sessions from a mod.
- cmd.account.plan — current user plan
No way for a mod to know what plan the user is on. Useful for mods that want to adapt their behavior (e.g. warn when approaching limits, suggest model alternatives based on what's available on the plan).
Use Case
No response
Additional Context
No response
How important is this to you?
None
Feature Description
Part 1 — UI / Design (high priority)
These are foundational. Better UI primitives make every other mod feature more useful. That's why they come first.
1.
cmd.ui.panel()/cmd.ui.divider()— native layout helpersProblem: Every mod that wants to display a panel or separator has to rewrite the same ~50 lines of utilities (terminal width handling, ANSI, padding). There's no visual consistency across community mods.
Use case: Any mod that displays structured output in the feed currently duplicates the same layout boilerplate. A shared
cmd.ui.panel(['line 1'], { title: 'my-mod' })andcmd.ui.divider()would give all mods a consistent look for free.2.
cmd.ui.spinner()— native spinnersProblem: There's no way to show a loading indicator during async work. Packages like
oradon't work inside the harness sandbox.Use case: A mod that does any async operation at startup (network call, file scan, etc.) has no way to tell the user it's working. A native spinner would be the most basic UX expectation.
3.
cmd.ui.table()— structured data displayProblem: Displaying a formatted table requires manual
.padEnd()per column, which breaks as soon as data changes or the terminal is too narrow.Use case: Any mod that shows structured data with multiple columns (name, value, status, etc.) would benefit from a standard table primitive rather than fragile manual padding.
4. Structured
cmd.ui.setStatus()with colored badges (footer)Problem:
setStatus()only supports plain text in the footer. No color, no icon, no badge styling.Use case: A mod that tracks some state would benefit from being able to show a colored, iconified badge in the footer (
● activein green, a counter in yellow) rather than unformatted text.5.
cmd.ui.widget()— actually wired in the TUIProblem:
cmd.ui.widget()exists in the API and is used in community mods (e.g. David Thyresson's weather mod), but it's currently a no-op — the widget renders nowhere.Use case: Any mod that wants to show persistent information above the editor (status, live counter, etc.) is currently blocked. The code exists; it just needs to be wired up in the TUI.
6.
w.update()— update a widget without recreating itProblem: To update a widget's content, you have to
.dispose()it and create a new one. This causes flickering and unnecessary boilerplate.Use case: Any widget displaying live or periodically refreshed data needs to update its content without destroying and recreating the whole component.
7. ANSI / color support in dialogs (
confirm,select,notify)Problem: Dialog text in
cmd.ui.confirm(),cmd.ui.select(), andcmd.ui.notify()is rendered as plain text — ANSI escape codes are not parsed.Use case: A confirmation dialog that visually distinguishes a dangerous action (red/bold title, colored options) is much clearer than a plain-text prompt. Color in dialogs is a basic UX expectation.
8.
cmd.ui.confirm()with custom button labelsProblem:
cmd.ui.confirm()always shows "OK" and "Cancel". There's no way to customize the button labels.Use case: Any confirmation that involves a specific action ("Delete", "Overwrite", "Enable") should be able to label its buttons accordingly rather than relying on the generic "OK".
9.
cmd.ui.progress()— progress bar for long operationsProblem: There's no way to show progress during a multi-step or time-consuming operation. The user has no feedback while the mod is working.
Use case: Any mod that processes multiple items sequentially or does a long async operation should be able to show a progress bar rather than leaving the user wondering if it's stuck.
10.
cmd.ui.menu()— interactive select with groups and searchProblem:
cmd.ui.select()is basic — no groups, no filtering, no advanced keyboard navigation.Use case: Any mod presenting a long list of options would benefit from a searchable, keyboard-navigable menu rather than a flat list the user has to scroll through.
11.
cmd.ui.clearFeed()— clear the feedProblem: There's no way to clear old messages from the feed. A mod that displays updates periodically accumulates lines that stay forever.
Use case: A mod that shows a regularly updated report should be able to clear its previous output and redisplay cleanly, rather than appending duplicate blocks on every update.
12.
cmd.ui.spacing()— explicit spacingProblem: Adding blank lines between display blocks currently requires
console.log(""). This is non-standard and bypasses the API.Use case: Any mod that displays multiple panels or sections needs a clean, idiomatic way to add vertical spacing.
13. Theming / shared color palette across mods
Problem: Every mod hardcodes its own colors. There's no way to share a theme across multiple mods, or to let the user customize the visual style.
Use case: An author publishing a set of related mods would want them to share a consistent visual identity without duplicating ANSI constants across every file. Users would benefit from being able to adjust colors to match their terminal theme.
14.
cmd.ui.push()— more prominent push notificationProblem:
cmd.ui.notify()adds a message to the feed, which gets lost in the scroll. There's no way to attract the user's attention more visibly.Use case: A mod that needs to alert the user about something important (a threshold crossed, an error detected) should have a way to show a more prominent notification that doesn't get buried in feed history.
Part 2 — Lifecycle, Hooks & Persistence
15.
cmd.globalStore— cross-session key-value storeProblem: There is no way to persist data across sessions without writing a JSON file via
cmd.exec("bash -c 'cat > ...'"). This works but it's a workaround, not an API.Use case: Any mod that wants to remember something between sessions (counters, preferences, history) currently has to manage raw files manually. A simple
cmd.globalStore.set/getwould be the standard path.16.
cmd.setInterval()— periodic refresh with automatic cleanupProblem: Mods that need periodic refresh (clock, live data, etc.) each implement their own
setInterval/clearIntervaltied toonSessionStart/onSessionEnd. It's identical boilerplate in every mod.Use case: Any mod with a periodic refresh cycle should be able to register it in one line and have the cleanup handled automatically at session end, rather than reimplementing the same lifecycle pattern every time.
17.
cmd.setFlag()— mutable flags at runtimeProblem: Flags (
cmd.addFlag) cannot be updated at runtime. If a mod exposes a configurable option via a slash command, it must use a closure variable — not a real flag.Use case: A mod configurable via
/my-mod option valueshould be able to update a real flag value live, so the next refresh picks it up immediately without a restart.18.
afterToolCall— reliabletoolNameandinputin hook payloadProblem: The docs say
afterToolCallreceives{toolCallId, toolName, input, result}, but in practicetoolNameandinputdon't seem consistently present. Mods end up guessing field names (input.file_path || input.path || input.file), which is fragile.Use case: Any mod reacting to specific tool calls needs to reliably branch on
toolNameand readinputwithout heuristics. This may just be a documentation or typings issue — but it should be verified and guaranteed.19.
beforeToolBatch— view the full batch before executionProblem:
beforeToolCallfires per tool call. There's no way to analyze the full set of planned actions before any of them execute.Use case: A safety-oriented mod that wants to warn the user when many actions are planned at once needs to see the full batch upfront — not intercept each call individually after execution has already started.
20.
onStopwith a granularstopReasonProblem:
onStopfires when the model stops, but also when an injected turn (from astop_hook) ends. Distinguishing the two requires a custom state machine in every mod that needs it.Use case: A mod that only wants to react to a natural end-of-run (not to injected turns) needs to be able to filter on
stopReason === 'end_turn'without building a two-phase state machine.21.
afterModelResponse— hook on the model's final textProblem: There's no way to inspect or modify the model's response before it's shown to the user.
Use case: A mod that monitors model output for specific patterns (warnings, risky content, missing context) needs to be able to read — and optionally annotate — the response at the point where it's produced, before it reaches the feed.
22.
cmd.openBrowser()/cmd.openFile()— cross-platform helpersProblem: Opening a file or URL from a mod requires
cmd.exec({ command: 'open', args: [path] }), which is macOS-only and not part of the official API.Use case: Any mod that generates output (a report, a preview, a dashboard) and wants to open it for the user should be able to do so with a cross-platform API call rather than platform-specific shell commands.
23. Programmatic sub-agents from a mod
Problem: Only the model can launch sub-agents via the
agenttool. A mod has no way to orchestrate parallel workers or delegate work to a dedicated sub-agent.Use case: A mod that needs to run background analysis or parallel processing on independent sub-tasks currently has no API path to do so — the orchestration logic has to live entirely in the model's prompt instead.
Addendum - a few more gaps I forgot to include:
The /model command shows model names, but the display names don't match the IDs the API actually accepts. There's no way for a mod to programmatically get the list of valid model identifiers to use with cmd.setModel().
No way to get input/output cost per token from within a mod. Mods that track or estimate cost have to hardcode price tables manually and keep them up to date themselves.
The model_request_end event gives per-turn token usage, but there's no way to access cumulative usage for the current session or across sessions from a mod.
No way for a mod to know what plan the user is on. Useful for mods that want to adapt their behavior (e.g. warn when approaching limits, suggest model alternatives based on what's available on the plan).
Use Case
No response
Additional Context
No response
How important is this to you?
None