Plugin API reference¶
Every value on this page is read out of the Whittl build it was generated from, so it cannot drift from what the plugin loader accepts.
For what to do with it, see Plugins and the plugin format.
=== WHITTL PLUGIN API 1 (generated from this build) ===
A plugin is a folder with manifest.json. The manifest lists CONTRIBUTIONS, each of one type below; a plugin may contribute several. (A manifest with top-level kind/entry instead of a contributions list is read as one contribution.)
CONTRIBUTION TYPES (contribution key: type)
tool - A function the AI can call while it builds. run(args) -> str, or run(args, context).
runs: subprocess
requires: entry optional: name, parameters, context, examples, timeout
* Offered to the AI beside Whittl's built-in tools, under its name. The description is the only thing telling the model when to use it.
* The manifest examples are RUN and are the acceptance test.
* One plugin may contribute several tools; give each its own name.
panel - A widget Whittl shows on one of its surfaces. create_panel(context) -> QWidget.
runs: in_process on the interface thread
requires: entry optional: title, placement, order
* Never offered to the AI. Verified by building it once in an offscreen process before it is ever loaded.
* placement is tab (default), dialog or statusbar.
* order (an integer, default 100) decides where a tab goes: lower first. Code is 0; Whittl's own Assets, Archives, Terminal and Help tabs use 5, 8, 10 and 20.
* Take colours from context.colors() and subscribe to the events you display, or the panel goes stale.
menu_action - An entry in the Edit > Plugins menu that runs a function. The function receives the same context a panel does.
runs: in_process on the interface thread
requires: entry, function, label
* For something done on demand: export a file, open a folder, reset a state. Keep it fast - the window waits for it.
* Return a string and it is shown in the status bar.
hook - A function Whittl calls when something happens: a generation starting or finishing, a project opening, a run starting.
runs: in_process on a helper thread of Whittl's, with a 3 second deadline - never touch a widget from a hook; record what you saw and let a panel poll
requires: entry, function, point
* The function receives one dict, the payload for that point.
* generation.before may return a string; it is appended to the prompt as guidance. Every other return value is ignored.
* A hook that raises three times, or one that does not return within 3 seconds, is switched off for the session and the reason is logged.
skill - A skill file (markdown with the usual front matter) that joins the skill library while the plugin is enabled.
runs: static
requires: file
* Same format as ~/.whittl/skills/. Triggers and budgets apply exactly as they do to any other skill.
* Disabling the plugin removes the skill.
HOOK POINTS (a hook contribution's 'point')
generation.before - A generation is about to start.
thread: a helper thread; the window waits up to 3 seconds
payload keys: message, target, project_id, files
may return: a string appended to the prompt as extra guidance
generation.after - A generation finished, successfully or not.
thread: a helper thread; the caller waits up to 3 seconds
payload keys: message, target, project_id, files, cancelled
project.opened - A different project is now open.
thread: a helper thread; the window waits up to 3 seconds
payload keys: project_id, name, target
run.before - The user pressed Run.
thread: a helper thread; the window waits up to 3 seconds
payload keys: project_id, files
PLACEMENTS for a panel (contribution key: placement)
tab - its own tab in the preview pane. The default.
dialog - a window opened from the Edit > Plugins menu. For something consulted occasionally rather than watched.
statusbar - a small always-visible widget in the status bar, capped at 320 pixels. For a live number or state; keep the text short.
A panel may not be placed anywhere else. These are the surfaces Whittl offers.
A dialog panel is opened from Edit > Plugins; a tab is reached by its tab and a statusbar panel is always visible.
PERMISSIONS (manifest key: permissions) - DISCLOSURE, not enforcement. Declare what the code really does.
files - reads or writes files outside the project
network - makes network requests
hardware - touches devices: camera, serial, audio
subprocess - runs other programs
CONTEXT KEYS for a tool (contribution key: context)
project_dir - absolute path of the user's project on disk
files - {filename: contents} for the project. The WHOLE project
target - pyside6, flet, customtkinter, general or plugin
LIMITS
api_version - this Whittl provides 1; declare it in the manifest
plugin name - lowercase letters, digits, underscores, 2-40 chars, starts with a letter (tool names likewise)
panel title - at most 24 characters
panel order - integer 0-1000, lower mounts first (default 100)
reserved tab titles (a TAB panel may not use these): code, assets, archives, terminal, help
timeout - seconds, at most 120 (default 30)
returned text - truncated at 100000 characters
reserved names (a tool may NOT be called these): bash, create_file, delete_file, download_file, edit_code, edit_function, glob, list_files, load_skill, multi_edit, probe_app, question, read_code, run_code, run_script, search_code, str_replace_based_edit_tool, syntax_check, web_fetch, web_search
WHAT A PANEL'S OR MENU ACTION'S context OFFERS - this is the whole surface, nothing else about Whittl is reachable:
context.archives() -> 'Dict[str, Any]' The open project's archives - snapshots of its code and assets - as ``entries``, oldest first, each with ``index`` (what the actions take), ``version``, ``name``, ``timestamp`` (ISO 8601), ``file_count``, ``total_lines``, ``asset_count`` and ``has_assets``.
context.archives_create(name: 'str' = '') -> 'bool' Save a snapshot of the open project's code and assets.
context.archives_delete(index: 'int') -> 'bool' Delete an archive and its files on disk.
context.archives_restore(index: 'int') -> 'bool' Put an archive's code back in the editor.
context.assets() -> 'Dict[str, Any]' The open project's assets: ``folder`` (the assets directory, "" when no project is open), ``project_folder``, and ``entries`` sorted by name, each with ``name``, ``path``, ``size``, ``is_image`` and ``source`` - "user" (the user's, protected from regeneration), "ai" (regenerable) or "unknown".
context.assets_delete(paths: 'List[str]') -> 'Dict[str, Any]' Delete assets.
context.assets_import(paths: 'List[str]') -> 'Dict[str, Any]' Copy files into the project's assets folder and mark them the user's.
context.assets_rename(path: 'str', new_name: 'str') -> 'Dict[str, Any]' Rename an asset in place, keeping its provenance.
context.assets_set_source(names: 'List[str]', source: 'str') -> 'bool' Mark assets as "user" (protected from regeneration) or "ai".
context.chat_prefill(text: 'str') -> 'bool' Put text in the chat input and focus it, WITHOUT sending: the user still sends it.
context.colors() -> 'Dict[str, str]' The current theme palette, as a name -> "#rrggbb" mapping.
context.console() -> 'Dict[str, Any]' The Terminal transcript Whittl keeps: ``generation`` (bumped on every clear) and ``entries``, oldest first, each with ``seq``, ``kind`` (stdout, stderr, command or info) and ``text``.
context.console_clear() -> 'bool' Empty the Terminal transcript for every viewer.
context.console_write(text: 'str', kind: 'str' = 'stdout') -> 'bool' Append text to the Terminal transcript, for every viewer.
context.get_setting(key: 'str', default: 'Any' = None) -> 'Any' Read a value this plugin stored.
context.icon(name: 'str', color: 'Optional[str]' = None, size: 'int' = 16) One of Whittl's own icons (Phosphor names: "plus", "image", "arrows-clockwise", "trash", ...) as a QIcon tinted to ``color``, or None when the host has none.
context.log(message: 'str') -> 'None' Print a line tagged with this plugin's name, for the terminal.
context.model() -> 'Dict[str, Any]' The model Whittl is talking to right now: ``backend``, ``model`` (its id), ``context_window`` (tokens it can hold, 0 when unknown) and ``window_source`` ("provider", or "num_ctx" when the Ollama setting is the smaller limit).
context.project() -> 'Dict[str, Any]' The open project: ``id``, ``name``, ``dir``, ``target``, ``files`` (a name -> source mapping).
context.set_setting(key: 'str', value: 'Any') -> 'bool' Persist a value for this plugin.
context.subscribe(event: 'str', callback: 'Callable[[], None]') -> 'None' Call ``callback`` when ``event`` happens.
context.usage() -> 'List[Dict[str, Any]]' Recorded API calls, oldest first.
context.usage_summary() -> 'Dict[str, Any]' Totals for the current session: ``requests``, ``input_tokens``, ``output_tokens``, ``cost``, and ``by_model`` / ``by_backend`` maps.
context.version Whittl's version string.
events subscribe() accepts: theme, usage, project, console, assets, archives.
Where these come from¶
| Thing | Defined in |
|---|---|
| kinds, placements, permissions, context keys, limits | core/plugin_manager.py |
what a panel's context offers |
core/plugin_context.py |
| the events a panel can subscribe to | core/plugin_context.py |
A plugin whose manifest breaks any rule above is listed in Edit > Plugins with the reason, rather than silently failing to appear.
Generated from Whittl 2.6.0.