* Add get_commands RPC for headless clients
Headless clients like Emacs can now query which commands are available.
Previously they could only discover file-based prompt templates by
scanning the filesystem; extension commands and skills were invisible.
The response includes each command's name, description, and source
(extension, template, or skill). Commands appear in the same order
as the TUI's autocomplete: extension commands first, then templates,
then skills.
Built-in TUI commands (/settings, /fork, etc.) are excluded since
they require the interactive UI. Commands like /compact have dedicated
RPC equivalents instead.
* Add location and path to get_commands response
Clients can show where commands come from (user/project/path) and
display file paths in tooltips. The data is already available on
templates and skills - just exposing it.
Move setup callback handling from interactive/rpc modes into AgentSession.newSession().
After setup() runs, sync agent state via replaceMessages() so the LLM has context
and the UI renders the messages properly.
fixes#968
- Add `-path` force-exclude pattern (exact path match, highest precedence)
- Change `+path` force-include to exact path match (no glob)
- Manifest-excluded resources are now hidden from config (not toggleable)
- Config toggle uses `+` to enable and `-` to disable
- Settings paths resolve relative to settings.json location:
- Global: relative to ~/.pi/agent
- Project: relative to .pi
- Add baseDir to PathMetadata for proper relative path computation
- Update tests for new base directory and pattern behavior
fixes#951
- Merged theme.md content into themes.md
- Added hot reload documentation
- Updated all references from theme.md to themes.md
- Fixed outdated info (vars not defs, complete example with all 50 tokens)
- Removed dev-focused Implementation section
* Add session renaming in interactive mode resume picker
Session list now displays last message timestamp as modified time
instead of file mtime. Ctrl+N enters rename mode in the interactive
resume picker, allowing quick session renaming without leaving the
selector. Rename hint is shown only in interactive mode, not in the
CLI --resume picker./
* Add docs entry for renaming in picker
* Update shortcut to ctrl+r for session renaming
* fix(coding-agent): HTML export sidebar click scrolls instead of truncating branch
Previously, clicking a message in the sidebar tree would set that message
as the new leaf, causing getPath() to only return messages up to that point
and hiding all messages below it.
Now handleTreeNodeClick() checks if the clicked entry is on the current path:
- If yes: just scrolls to it without re-rendering
- If no: finds the actual leaf of that branch and navigates to it, then
scrolls to the clicked message
Added childrenMap for parent->children lookup and findBranchLeaf() to
traverse down to a branch's leaf.
* fix(coding-agent): HTML export sidebar click scrolls instead of truncating branch
Previously, clicking a message in the sidebar tree would set that message
as the new leaf, causing getPath() to only return messages up to that point
and hiding all messages below it.
Now handleTreeNodeClick() checks if the clicked entry is on the current path:
- If yes: scrolls to it and updates the active marker
- If no: finds the branch's leaf, navigates to it, then scrolls to clicked message
Adds currentTargetId to track the selected entry separately from currentLeafId
(which branch to display), so the active marker follows user selection.
* most recent path wins
* reuse method
* revert
* feat(coding-agent): highlight active path in HTML export sidebar
- Add subtle accent background tint to in-path nodes
- Dim off-path nodes to 50% opacity (restore on hover)
- Makes current branch visually distinct in tree navigation
* docs(coding-agent): move changelog entry to Unreleased and add attribution
* chore(coding-agent): remove dead code and fix changelog attribution
- Remove unused childrenMap, findBranchLeaf, handleTreeNodeClick, scrollToEntry
- Split changelog entry: navigation (#853 by @mitsuhiko), highlighting (#929 by @hewliyang)
Allows custom models to specify which upstream providers OpenRouter
should route requests to via the `openRouterRouting` field in model
definitions.
Supported fields:
- `only`: list of provider slugs to exclusively use
- `order`: list of provider slugs to try in order
Adds a new 'pi config' command with a TUI to list and toggle package
resources (extensions, skills, prompts, themes).
- Displays resources grouped by source (packages, user, project)
- Subgroups by resource type (Extensions, Skills, Prompts, Themes)
- Toggle enabled/disabled state with space
- Filter resources by typing
- Supports +pattern for force-include, !pattern for exclude
- Properly reads exclusion patterns from settings.json
fixes#938
For temporary npm extensions (-e npm:...):
- Unpinned packages: fetch latest version from registry and reinstall if newer
- Pinned packages: reinstall if cached version doesn't match
- Add resetApiProviders() to clear and re-register built-in providers
- Add createAssistantMessageEventStream() factory for extensions
- Add streamSimple support in ProviderConfig for custom API implementations
- Call resetApiProviders() on /reload to clean up extension providers
- Add custom-provider.md documentation
- Add custom-provider.ts example with full Anthropic implementation
- Update extensions.md with streamSimple config option
When set to true, the skill is hidden from the system prompt, preventing
agentic invocation. Users can still invoke explicitly via /skill:name.
Also fixes pre-existing test bug where source expectation was wrong.
Fixes#927
- Create shared diagnostics.ts with ResourceCollision and ResourceDiagnostic types
- Update loadSkills() to return diagnostics instead of warnings
- Remove SkillWarning type and skillWarningsToDiagnostics() conversion
- Update skills.test.ts to use diagnostics
- Package deduplication: same package in global+project, project wins
- Collision detection for skills, prompts, and themes with ResourceCollision type
- PathMetadata tracking with parent directory lookup for file paths
- Display improvements: section headers, sorted groups, accent colors for packages
- pi list shows full paths below package names
- Extension loader discovers files in directories without index.ts
- In-memory SettingsManager properly tracks project settings
fixes#645
Previously, user filters completely replaced manifest filtering. Now:
1. Manifest patterns are applied first (defines what package provides)
2. User patterns are applied on top (narrows down further)
This means if a manifest excludes 10 extensions and user adds one more
exclusion, all 11 are excluded (not just the user's one).
- Manifest extensions/skills/prompts/themes arrays now support glob patterns
- Use !pattern for exclusions (e.g., '!**/deprecated/*')
- Enables packages to bundle dependencies and selectively include resources
- Support glob patterns and ! exclusions in package filter arrays
- Support glob patterns and ! exclusions in top-level settings arrays
- Add helper functions: isPattern, hasPatterns, collectFiles, collectSkillEntries, applyPatterns
- Add resolveLocalEntries for pattern-aware resolution of top-level arrays
- Add applyPackageFilter and collectAllPackageFiles for package filter patterns
- Add comprehensive tests for both top-level and package filter patterns
- Add PackageSource type for npm/git sources with optional filtering
- Migrate npm:/git: sources from extensions to packages array
- Add getPackages(), setPackages(), setProjectPackages() methods
- Update package-manager to resolve from packages array
- Support selective loading: extensions, skills, prompts, themes per package
- Update pi list to show packages
- Add migration tests for settings
closes#645
- Add ParsedSkillBlock interface and parseSkillBlock() function
- Change skill expansion to use XML-style <skill> tags
- Add SkillInvocationMessageComponent for collapsible display
- Collapsed: single line with skill name and expand hint
- User message rendered separately after skill block
Fixes#894
There's only ever one bindings instance per session, so the Set/Array
approach was unnecessary. Changed from Set<ExtensionErrorListener> to
optional single listener.
Header values in models.json now resolve using the same logic as apiKey:
- Environment variable names are resolved to their values
- Shell commands prefixed with ! are executed
- Literal values are used directly
This is a minor breaking change: if a header value accidentally matches
an env var name, it will now resolve to that env var's value.
Fixes#909
- Add progress callbacks to PackageManager for TUI status during install/remove/update
- Add extension conflict detection (tools, commands, flags with same names)
- Accept raw GitHub/GitLab URLs without git: prefix
- Add tests for package-manager.ts and resource-loader.ts
- Add empty fixture directories for skills tests
- Add ResourceLoader interface and DefaultResourceLoader implementation
- Add PackageManager for npm/git extension sources with install/remove/update
- Add session.reload() and session.bindExtensions() APIs
- Add /reload command in interactive mode
- Add CLI flags: --skill, --theme, --prompt-template, --no-themes, --no-prompt-templates
- Add pi install/remove/update commands for extension management
- Refactor settings.json to use arrays for skills, prompts, themes
- Remove legacy SkillsSettings source flags and filters
- Update SDK examples and documentation for ResourceLoader pattern
- Add theme registration and loadThemeFromPath for dynamic themes
- Add getShellEnv to include bin dir in PATH for bash commands
Error messages for missing credentials and shell config now use
getAuthPath() and getSettingsPath() instead of hardcoded ~/.pi/agent/
paths, so they correctly reflect PI_CODING_AGENT_DIR when set.
Add markdown.codeBlockIndent setting to customize indentation prefix for
rendered code blocks. Default remains 2 spaces for visual clarity, but
setting to empty string removes indentation for easier copy/paste of
code snippets to scripts, editors, or other tools.
Changes:
- tui: add optional codeBlockIndent to MarkdownTheme interface
- coding-agent: add MarkdownSettings with codeBlockIndent property
- coding-agent: compose theme with settings at call sites (no global state)
- coding-agent: update message components to accept optional MarkdownTheme
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>