mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 05:02:14 +00:00
Improve system prompt docs, clean up theme/skills/hooks docs, fix toolResults type
- System prompt: clearer pointers to specific doc files - theme.md: added thinkingXhigh, bashMode tokens, fixed Theme class methods - skills.md: rewrote with better framing, examples, and skill repositories - hooks.md: fixed timeout/error handling docs, added custom tool interception note - Breaking: turn_end event toolResults changed from AppMessage[] to ToolResultMessage[]
This commit is contained in:
parent
5cc0126991
commit
5e5bdadbf9
8 changed files with 232 additions and 141 deletions
|
|
@ -4,6 +4,7 @@ import type {
|
||||||
AssistantMessageEvent,
|
AssistantMessageEvent,
|
||||||
Message,
|
Message,
|
||||||
Model,
|
Model,
|
||||||
|
ToolResultMessage,
|
||||||
UserMessage,
|
UserMessage,
|
||||||
} from "@mariozechner/pi-ai";
|
} from "@mariozechner/pi-ai";
|
||||||
|
|
||||||
|
|
@ -87,7 +88,7 @@ export type AgentEvent =
|
||||||
| { type: "agent_end"; messages: AppMessage[] }
|
| { type: "agent_end"; messages: AppMessage[] }
|
||||||
// Turn lifecycle - a turn is one assistant response + any tool calls/results
|
// Turn lifecycle - a turn is one assistant response + any tool calls/results
|
||||||
| { type: "turn_start" }
|
| { type: "turn_start" }
|
||||||
| { type: "turn_end"; message: AppMessage; toolResults: AppMessage[] }
|
| { type: "turn_end"; message: AppMessage; toolResults: ToolResultMessage[] }
|
||||||
// Message lifecycle - emitted for user, assistant, and toolResult messages
|
// Message lifecycle - emitted for user, assistant, and toolResult messages
|
||||||
| { type: "message_start"; message: AppMessage }
|
| { type: "message_start"; message: AppMessage }
|
||||||
// Only emitted for assistant messages during streaming
|
// Only emitted for assistant messages during streaming
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved system prompt documentation section with clearer pointers to specific doc files for custom models, themes, skills, hooks, custom tools, and RPC.
|
||||||
|
|
||||||
|
- Cleaned up documentation: `theme.md` (added missing color tokens), `skills.md` (rewrote with better framing and examples), `hooks.md` (fixed timeout/error handling docs, added examples).
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- **Hooks**: `turn_end` event's `toolResults` type changed from `AppMessage[]` to `ToolResultMessage[]`. If you have hooks that handle `turn_end` events and explicitly type the results, update your type annotations.
|
||||||
|
|
||||||
## [0.23.2] - 2025-12-17
|
## [0.23.2] - 2025-12-17
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
||||||
|
|
@ -488,66 +488,41 @@ Usage: `/component Button "onClick handler" "disabled support"`
|
||||||
|
|
||||||
### Skills
|
### Skills
|
||||||
|
|
||||||
Skills are instruction files loaded on-demand when tasks match their descriptions. Compatible with Claude Code and Codex CLI skill formats.
|
Skills are self-contained capability packages that the agent loads on-demand. A skill provides specialized workflows, setup instructions, helper scripts, and reference documentation for specific tasks. Skills are loaded when the agent decides a task matches the description, or when you explicitly ask to use one.
|
||||||
|
|
||||||
**Skill locations:**
|
**Skill locations:**
|
||||||
- Pi user: `~/.pi/agent/skills/**/SKILL.md` (recursive, colon-separated names)
|
- Pi user: `~/.pi/agent/skills/**/SKILL.md` (recursive)
|
||||||
- Pi project: `.pi/skills/**/SKILL.md` (recursive, colon-separated names)
|
- Pi project: `.pi/skills/**/SKILL.md` (recursive)
|
||||||
- Claude Code user: `~/.claude/skills/*/SKILL.md` (one level)
|
- Claude Code: `~/.claude/skills/*/SKILL.md` and `.claude/skills/*/SKILL.md`
|
||||||
- Claude Code project: `.claude/skills/*/SKILL.md` (one level)
|
|
||||||
- Codex CLI: `~/.codex/skills/**/SKILL.md` (recursive)
|
- Codex CLI: `~/.codex/skills/**/SKILL.md` (recursive)
|
||||||
|
|
||||||
Later locations win on name collisions (Pi skills override Claude/Codex).
|
|
||||||
|
|
||||||
Pi skills in subdirectories use colon-separated names: `~/.pi/agent/skills/db/migrate/SKILL.md` → `db:migrate`
|
|
||||||
|
|
||||||
**Format:**
|
**Format:**
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
description: Extract text and tables from PDF files
|
description: Web search via Brave Search API. Use for documentation, facts, or web content.
|
||||||
---
|
---
|
||||||
|
|
||||||
# PDF Processing
|
# Brave Search
|
||||||
|
|
||||||
Use `pdftotext` for plain text extraction.
|
## Setup
|
||||||
For tables, use `tabula-py`.
|
\`\`\`bash
|
||||||
|
cd {baseDir} && npm install
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
Helper scripts: {baseDir}/scripts/
|
## Usage
|
||||||
|
\`\`\`bash
|
||||||
|
{baseDir}/search.js "query" # Basic search
|
||||||
|
{baseDir}/search.js "query" --content # Include page content
|
||||||
|
\`\`\`
|
||||||
```
|
```
|
||||||
|
|
||||||
- `description`: Required. Shown in system prompt for agent to decide when to load.
|
- `description`: Required. Determines when the skill is loaded.
|
||||||
- `name`: Optional. Overrides directory name.
|
- `{baseDir}`: Placeholder for the skill's directory.
|
||||||
- `{baseDir}`: Placeholder for the skill's directory. Agent substitutes it when following instructions.
|
|
||||||
|
|
||||||
**How it works:**
|
**Disable skills:** `pi --no-skills` or set `skills.enabled: false` in settings.
|
||||||
|
|
||||||
Skills are listed in the system prompt with descriptions:
|
See [docs/skills.md](docs/skills.md) for details, examples, and links to skill repositories.
|
||||||
|
|
||||||
```
|
|
||||||
<available_skills>
|
|
||||||
- pdf-extract: Extract text and tables from PDF files
|
|
||||||
File: ~/.pi/agent/skills/pdf-extract/SKILL.md
|
|
||||||
Base directory: ~/.pi/agent/skills/pdf-extract
|
|
||||||
</available_skills>
|
|
||||||
```
|
|
||||||
|
|
||||||
Agent uses `read` tool to load full instructions when needed.
|
|
||||||
|
|
||||||
**Disable skills:**
|
|
||||||
|
|
||||||
CLI: `pi --no-skills`
|
|
||||||
|
|
||||||
Settings (`~/.pi/agent/settings.json`):
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"skills": {
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See [docs/skills.md](docs/skills.md) for details.
|
|
||||||
|
|
||||||
### Hooks
|
### Hooks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
|
|
||||||
Hooks are TypeScript modules that extend the coding agent's behavior by subscribing to lifecycle events. They can intercept tool calls, prompt the user for input, modify results, and more.
|
Hooks are TypeScript modules that extend the coding agent's behavior by subscribing to lifecycle events. They can intercept tool calls, prompt the user for input, modify results, and more.
|
||||||
|
|
||||||
|
**Example use cases:**
|
||||||
|
- Block dangerous commands (permission gates for `rm -rf`, `sudo`, etc.)
|
||||||
|
- Checkpoint code state (git stash at each turn, restore on `/branch`)
|
||||||
|
- Protect paths (block writes to `.env`, `node_modules/`, etc.)
|
||||||
|
- Modify tool output (filter or transform results before the LLM sees them)
|
||||||
|
- Inject messages from external sources (file watchers, webhooks, CI systems)
|
||||||
|
|
||||||
|
See [examples/hooks/](../examples/hooks/) for working implementations.
|
||||||
|
|
||||||
## Hook Locations
|
## Hook Locations
|
||||||
|
|
||||||
Hooks are automatically discovered from two locations:
|
Hooks are automatically discovered from two locations:
|
||||||
|
|
@ -33,7 +42,7 @@ You can also add explicit hook paths in `~/.pi/agent/settings.json`:
|
||||||
```
|
```
|
||||||
|
|
||||||
- `hooks`: Additional hook file paths (supports `~` expansion)
|
- `hooks`: Additional hook file paths (supports `~` expansion)
|
||||||
- `hookTimeout`: Timeout in milliseconds for non-interactive hook operations (default: 30000)
|
- `hookTimeout`: Timeout in milliseconds for hook operations (default: 30000). Does not apply to `tool_call` events, which have no timeout since they may prompt the user.
|
||||||
|
|
||||||
## Writing a Hook
|
## Writing a Hook
|
||||||
|
|
||||||
|
|
@ -51,23 +60,17 @@ export default function (pi: HookAPI) {
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
Create a hooks directory and initialize it:
|
Create a hooks directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Global hooks
|
# Global hooks
|
||||||
mkdir -p ~/.pi/agent/hooks
|
mkdir -p ~/.pi/agent/hooks
|
||||||
cd ~/.pi/agent/hooks
|
|
||||||
npm init -y
|
|
||||||
npm install @mariozechner/pi-coding-agent
|
|
||||||
|
|
||||||
# Or project-local hooks
|
# Or project-local hooks
|
||||||
mkdir -p .pi/hooks
|
mkdir -p .pi/hooks
|
||||||
cd .pi/hooks
|
|
||||||
npm init -y
|
|
||||||
npm install @mariozechner/pi-coding-agent
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Hooks are loaded using [jiti](https://github.com/unjs/jiti), so TypeScript works without compilation.
|
Then create `.ts` files directly in these directories. Hooks are loaded using [jiti](https://github.com/unjs/jiti), so TypeScript works without compilation. The import from `@mariozechner/pi-coding-agent/hooks` resolves to the globally installed package automatically.
|
||||||
|
|
||||||
## Events
|
## Events
|
||||||
|
|
||||||
|
|
@ -121,7 +124,7 @@ Fired on startup and when session changes.
|
||||||
```typescript
|
```typescript
|
||||||
pi.on("session", async (event, ctx) => {
|
pi.on("session", async (event, ctx) => {
|
||||||
// event.entries: SessionEntry[] - all session entries
|
// event.entries: SessionEntry[] - all session entries
|
||||||
// event.sessionFile: string | null - current session file
|
// event.sessionFile: string | null - current session file (null with --no-session)
|
||||||
// event.previousSessionFile: string | null - previous session file
|
// event.previousSessionFile: string | null - previous session file
|
||||||
// event.reason: "start" | "switch" | "clear"
|
// event.reason: "start" | "switch" | "clear"
|
||||||
});
|
});
|
||||||
|
|
@ -171,24 +174,24 @@ pi.on("turn_start", async (event, ctx) => {
|
||||||
pi.on("turn_end", async (event, ctx) => {
|
pi.on("turn_end", async (event, ctx) => {
|
||||||
// event.turnIndex: number
|
// event.turnIndex: number
|
||||||
// event.message: AppMessage - assistant's response
|
// event.message: AppMessage - assistant's response
|
||||||
// event.toolResults: AppMessage[]
|
// event.toolResults: ToolResultMessage[] - tool results from this turn
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### tool_call
|
### tool_call
|
||||||
|
|
||||||
Fired before tool executes. **Can block.**
|
Fired before tool executes. **Can block.** No timeout (user prompts can take any time).
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
pi.on("tool_call", async (event, ctx) => {
|
pi.on("tool_call", async (event, ctx) => {
|
||||||
// event.toolName: "bash" | "read" | "write" | "edit" | "ls" | "find" | "grep"
|
// event.toolName: string (built-in or custom tool name)
|
||||||
// event.toolCallId: string
|
// event.toolCallId: string
|
||||||
// event.input: Record<string, unknown>
|
// event.input: Record<string, unknown>
|
||||||
return { block: true, reason: "..." }; // or undefined to allow
|
return { block: true, reason: "..." }; // or undefined to allow
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Tool inputs:
|
Built-in tool inputs:
|
||||||
- `bash`: `{ command, timeout? }`
|
- `bash`: `{ command, timeout? }`
|
||||||
- `read`: `{ path, offset?, limit? }`
|
- `read`: `{ path, offset?, limit? }`
|
||||||
- `write`: `{ path, content }`
|
- `write`: `{ path, content }`
|
||||||
|
|
@ -197,6 +200,8 @@ Tool inputs:
|
||||||
- `find`: `{ pattern, path?, limit? }`
|
- `find`: `{ pattern, path?, limit? }`
|
||||||
- `grep`: `{ pattern, path?, glob?, ignoreCase?, literal?, context?, limit? }`
|
- `grep`: `{ pattern, path?, glob?, ignoreCase?, literal?, context?, limit? }`
|
||||||
|
|
||||||
|
Custom tools are also intercepted with their own names and input schemas.
|
||||||
|
|
||||||
### tool_result
|
### tool_result
|
||||||
|
|
||||||
Fired after tool executes. **Can modify result.**
|
Fired after tool executes. **Can modify result.**
|
||||||
|
|
@ -274,7 +279,7 @@ console.log(`Working in: ${ctx.cwd}`);
|
||||||
|
|
||||||
### ctx.sessionFile
|
### ctx.sessionFile
|
||||||
|
|
||||||
Path to the session file, or `null` if running with `--no-session`.
|
Path to the current session file, or `null` when running with `--no-session` (ephemeral mode).
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
if (ctx.sessionFile) {
|
if (ctx.sessionFile) {
|
||||||
|
|
@ -490,7 +495,8 @@ In print mode, `select()` returns `null`, `confirm()` returns `false`, and `inpu
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
- If a hook throws an error, it's logged and the agent continues
|
- If a hook throws an error, it's logged and the agent continues
|
||||||
- If a `tool_call` hook errors or times out, the tool is **blocked** (fail-safe)
|
- If a `tool_call` hook throws an error, the tool is **blocked** (fail-safe)
|
||||||
|
- Other events have a timeout (default 30s); timeout errors are logged but don't block
|
||||||
- Hook errors are displayed in the UI with the hook path and error message
|
- Hook errors are displayed in the UI with the hook path and error message
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
@ -563,9 +569,9 @@ class HookRunner {
|
||||||
|
|
||||||
Key behaviors:
|
Key behaviors:
|
||||||
- `emit()` has a timeout (default 30s) for safety
|
- `emit()` has a timeout (default 30s) for safety
|
||||||
- `emitToolCall()` has **no timeout** (user prompts can take any amount of time)
|
- `emitToolCall()` has **no timeout** (user prompts can take any time)
|
||||||
- Errors in `emit()` are caught and reported via `onError()`
|
- Errors in `emit()` are caught, logged via `onError()`, and execution continues
|
||||||
- Errors in `emitToolCall()` propagate (causing tool to be blocked)
|
- Errors in `emitToolCall()` propagate, causing the tool to be blocked (fail-safe)
|
||||||
|
|
||||||
## Event Flow
|
## Event Flow
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,190 @@
|
||||||
# Skills
|
# Skills
|
||||||
|
|
||||||
Skills are instruction files that the agent loads on-demand for specific tasks.
|
Skills are self-contained capability packages that the agent loads on-demand. A skill provides specialized workflows, setup instructions, helper scripts, and reference documentation for specific tasks.
|
||||||
|
|
||||||
## Skill Locations
|
**Example use cases:**
|
||||||
|
- Web search and content extraction (Brave Search API)
|
||||||
|
- Browser automation via Chrome DevTools Protocol
|
||||||
|
- Google Calendar, Gmail, Drive integration
|
||||||
|
- PDF/DOCX processing and creation
|
||||||
|
- Speech-to-text transcription
|
||||||
|
- YouTube transcript extraction
|
||||||
|
|
||||||
Skills are discovered from these locations (in order of priority, later wins on name collision):
|
See [Skill Repositories](#skill-repositories) for ready-to-use skills.
|
||||||
|
|
||||||
1. `~/.codex/skills/**/SKILL.md` (Codex CLI user skills, recursive)
|
## When to Use Skills
|
||||||
2. `~/.claude/skills/*/SKILL.md` (Claude Code user skills)
|
|
||||||
3. `<cwd>/.claude/skills/*/SKILL.md` (Claude Code project skills)
|
|
||||||
4. `~/.pi/agent/skills/**/SKILL.md` (Pi user skills, recursive)
|
|
||||||
5. `<cwd>/.pi/skills/**/SKILL.md` (Pi project skills, recursive)
|
|
||||||
|
|
||||||
Skill names and descriptions are listed in the system prompt. When a task matches a skill's description, the agent uses the `read` tool to load it.
|
| Need | Solution |
|
||||||
|
|------|----------|
|
||||||
|
| Always-needed context (conventions, commands) | AGENTS.md |
|
||||||
|
| User triggers a specific prompt template | Slash command |
|
||||||
|
| Additional tool directly callable by the LLM (like read/write/edit/bash) | Custom tool |
|
||||||
|
| On-demand capability package (workflows, scripts, setup) | Skill |
|
||||||
|
|
||||||
## Creating Skills
|
Skills are loaded when:
|
||||||
|
- The agent decides the task matches a skill's description
|
||||||
|
- The user explicitly asks to use a skill (e.g., "use the pdf skill to extract tables")
|
||||||
|
|
||||||
A skill is a markdown file with YAML frontmatter containing a `description` field:
|
**Good skill examples:**
|
||||||
|
- Browser automation with helper scripts and CDP workflow
|
||||||
|
- Google Calendar CLI with setup instructions and usage patterns
|
||||||
|
- PDF processing with multiple tools and extraction patterns
|
||||||
|
- Speech-to-text transcription with API setup
|
||||||
|
|
||||||
|
**Not a good fit for skills:**
|
||||||
|
- "Always use TypeScript strict mode" → put in AGENTS.md
|
||||||
|
- "Review my code" → make a slash command
|
||||||
|
- Need user confirmation dialogs or custom TUI rendering → make a custom tool
|
||||||
|
|
||||||
|
## Skill Structure
|
||||||
|
|
||||||
|
A skill is a directory with a `SKILL.md` file. Everything else is freeform. Example structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
my-skill/
|
||||||
|
├── SKILL.md # Required: frontmatter + instructions
|
||||||
|
├── scripts/ # Helper scripts (bash, python, node)
|
||||||
|
│ └── process.sh
|
||||||
|
├── references/ # Detailed docs loaded on-demand
|
||||||
|
│ └── api-reference.md
|
||||||
|
└── assets/ # Templates, images, etc.
|
||||||
|
└── template.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### SKILL.md Format
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
description: Extract text and tables from PDF files
|
name: my-skill
|
||||||
|
description: What this skill does and when to use it. Be specific.
|
||||||
---
|
---
|
||||||
|
|
||||||
# PDF Processing Instructions
|
# My Skill
|
||||||
|
|
||||||
1. Use `pdftotext` to extract plain text
|
## Setup
|
||||||
2. For tables, use `tabula-py` or similar
|
|
||||||
3. Always verify extraction quality
|
|
||||||
|
|
||||||
Scripts are in: {baseDir}/scripts/
|
Run once before first use:
|
||||||
|
\`\`\`bash
|
||||||
|
cd {baseDir}
|
||||||
|
npm install
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
{baseDir}/scripts/process.sh <input>
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. First step
|
||||||
|
2. Second step
|
||||||
|
3. Third step
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontmatter Fields
|
### Frontmatter Fields
|
||||||
|
|
||||||
| Field | Required | Description |
|
| Field | Required | Description |
|
||||||
|-------|----------|-------------|
|
|-------|----------|-------------|
|
||||||
| `description` | Yes | Short description for skill selection |
|
| `description` | Yes | What the skill does and when to use it |
|
||||||
| `name` | No | Override skill name (defaults to filename or directory name) |
|
| `name` | No | Override skill name (defaults to directory name) |
|
||||||
|
|
||||||
The parser only supports single-line `key: value` syntax. Multiline YAML blocks are not supported.
|
The `description` is critical. It's shown in the system prompt and determines when the agent loads the skill. Be specific about both what it does and when to use it.
|
||||||
|
|
||||||
### Variables
|
### The `{baseDir}` Placeholder
|
||||||
|
|
||||||
Use `{baseDir}` as a placeholder for the skill's directory. The agent is told each skill's base directory and will substitute it when following the instructions.
|
Use `{baseDir}` to reference files in the skill's directory. The agent sees each skill's base directory and substitutes it when following instructions:
|
||||||
|
|
||||||
### Subdirectories
|
```markdown
|
||||||
|
Helper scripts: {baseDir}/scripts/
|
||||||
|
Config template: {baseDir}/assets/config.json
|
||||||
|
```
|
||||||
|
|
||||||
Pi and Codex skills in subdirectories use colon-separated names:
|
## Skill Locations
|
||||||
|
|
||||||
|
Skills are discovered from these locations (later wins on name collision):
|
||||||
|
|
||||||
|
1. `~/.codex/skills/**/SKILL.md` (Codex CLI, recursive)
|
||||||
|
2. `~/.claude/skills/*/SKILL.md` (Claude Code user, one level)
|
||||||
|
3. `<cwd>/.claude/skills/*/SKILL.md` (Claude Code project, one level)
|
||||||
|
4. `~/.pi/agent/skills/**/SKILL.md` (Pi user, recursive)
|
||||||
|
5. `<cwd>/.pi/skills/**/SKILL.md` (Pi project, recursive)
|
||||||
|
|
||||||
|
### Subdirectory Naming
|
||||||
|
|
||||||
|
Pi skills in subdirectories use colon-separated names:
|
||||||
- `~/.pi/agent/skills/db/migrate/SKILL.md` → `db:migrate`
|
- `~/.pi/agent/skills/db/migrate/SKILL.md` → `db:migrate`
|
||||||
- `<cwd>/.pi/skills/aws/s3/upload/SKILL.md` → `aws:s3:upload`
|
- `<cwd>/.pi/skills/aws/s3/upload/SKILL.md` → `aws:s3:upload`
|
||||||
|
|
||||||
## Claude Code Compatibility
|
## How Skills Work
|
||||||
|
|
||||||
Pi reads Claude Code skills from `~/.claude/skills/*/SKILL.md`. The `allowed-tools` and `model` frontmatter fields are ignored since Pi cannot enforce them.
|
1. At startup, pi scans skill locations and extracts names + descriptions
|
||||||
|
2. The system prompt includes a list of available skills with their descriptions
|
||||||
|
3. When a task matches, the agent uses `read` to load the full SKILL.md
|
||||||
|
4. The agent follows the instructions, using `{baseDir}` to reference scripts/assets
|
||||||
|
|
||||||
## Codex CLI Compatibility
|
This is progressive disclosure: only descriptions are always in context, full instructions load on-demand.
|
||||||
|
|
||||||
Pi reads Codex CLI skills from `~/.codex/skills/`. Unlike Claude Code skills (one level deep), Codex skills are scanned recursively, matching Codex CLI's behavior. Hidden files/directories (starting with `.`) and symlinks are skipped.
|
## Example: Web Search Skill
|
||||||
|
|
||||||
|
```
|
||||||
|
brave-search/
|
||||||
|
├── SKILL.md
|
||||||
|
├── search.js
|
||||||
|
└── content.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**SKILL.md:**
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: brave-search
|
||||||
|
description: Web search and content extraction via Brave Search API. Use for searching documentation, facts, or any web content.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Brave Search
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
cd {baseDir}
|
||||||
|
npm install
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Search
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
{baseDir}/search.js "query" # Basic search
|
||||||
|
{baseDir}/search.js "query" --content # Include page content
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Extract Page Content
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
{baseDir}/content.js https://example.com
|
||||||
|
\`\`\`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
**Claude Code**: Pi reads skills from `~/.claude/skills/*/SKILL.md`. The `allowed-tools` and `model` frontmatter fields are ignored.
|
||||||
|
|
||||||
|
**Codex CLI**: Pi reads skills from `~/.codex/skills/` recursively. Hidden files/directories and symlinks are skipped.
|
||||||
|
|
||||||
|
## Skill Repositories
|
||||||
|
|
||||||
|
For inspiration and ready-to-use skills:
|
||||||
|
|
||||||
|
- [Anthropic Skills](https://github.com/anthropics/skills) - Official skills for document processing (docx, pdf, pptx, xlsx), web development, and more
|
||||||
|
- [Pi Skills](https://github.com/badlogic/pi-skills) - Skills for web search, browser automation, Google APIs, transcription
|
||||||
|
|
||||||
## Disabling Skills
|
## Disabling Skills
|
||||||
|
|
||||||
CLI flag:
|
CLI:
|
||||||
```bash
|
```bash
|
||||||
pi --no-skills
|
pi --no-skills
|
||||||
```
|
```
|
||||||
|
|
||||||
Or in `~/.pi/agent/settings.json`:
|
Settings (`~/.pi/agent/settings.json`):
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"skills": {
|
"skills": {
|
||||||
|
|
@ -74,25 +192,3 @@ Or in `~/.pi/agent/settings.json`:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
description: Perform code review with security and performance analysis
|
|
||||||
---
|
|
||||||
|
|
||||||
# Code Review
|
|
||||||
|
|
||||||
Analyze:
|
|
||||||
|
|
||||||
## Security
|
|
||||||
- Input validation
|
|
||||||
- SQL injection
|
|
||||||
- XSS vulnerabilities
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
- Algorithm complexity
|
|
||||||
- Memory usage
|
|
||||||
- Query efficiency
|
|
||||||
```
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ Future-proofing for syntax highlighting support:
|
||||||
| `syntaxOperator` | Operators (`+`, `-`, etc) |
|
| `syntaxOperator` | Operators (`+`, `-`, etc) |
|
||||||
| `syntaxPunctuation` | Punctuation (`;`, `,`, etc) |
|
| `syntaxPunctuation` | Punctuation (`;`, `,`, etc) |
|
||||||
|
|
||||||
### Thinking Level Borders (5 colors)
|
### Thinking Level Borders (6 colors)
|
||||||
|
|
||||||
Editor border colors that indicate the current thinking/reasoning level:
|
Editor border colors that indicate the current thinking/reasoning level:
|
||||||
|
|
||||||
|
|
@ -84,11 +84,18 @@ Editor border colors that indicate the current thinking/reasoning level:
|
||||||
| `thinkingMinimal` | Border for minimal thinking |
|
| `thinkingMinimal` | Border for minimal thinking |
|
||||||
| `thinkingLow` | Border for low thinking |
|
| `thinkingLow` | Border for low thinking |
|
||||||
| `thinkingMedium` | Border for medium thinking |
|
| `thinkingMedium` | Border for medium thinking |
|
||||||
| `thinkingHigh` | Border for high thinking (most prominent) |
|
| `thinkingHigh` | Border for high thinking |
|
||||||
|
| `thinkingXhigh` | Border for xhigh thinking (most prominent, OpenAI codex-max only) |
|
||||||
|
|
||||||
These create a visual hierarchy: off → minimal → low → medium → high
|
These create a visual hierarchy: off → minimal → low → medium → high → xhigh
|
||||||
|
|
||||||
**Total: 44 color tokens** (all required)
|
### Bash Mode (1 color)
|
||||||
|
|
||||||
|
| Token | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `bashMode` | Editor border color when in bash mode (! prefix) |
|
||||||
|
|
||||||
|
**Total: 46 color tokens** (all required)
|
||||||
|
|
||||||
## Theme Format
|
## Theme Format
|
||||||
|
|
||||||
|
|
@ -420,8 +427,8 @@ class Theme {
|
||||||
|
|
||||||
// Text attributes (preserve current colors)
|
// Text attributes (preserve current colors)
|
||||||
bold(text: string): string
|
bold(text: string): string
|
||||||
dim(text: string): string
|
|
||||||
italic(text: string): string
|
italic(text: string): string
|
||||||
|
underline(text: string): string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -453,6 +460,7 @@ TUI components (like `Markdown`, `SelectList`, `Editor`) are in the `@mariozechn
|
||||||
export interface MarkdownTheme {
|
export interface MarkdownTheme {
|
||||||
heading: (text: string) => string;
|
heading: (text: string) => string;
|
||||||
link: (text: string) => string;
|
link: (text: string) => string;
|
||||||
|
linkUrl: (text: string) => string;
|
||||||
code: (text: string) => string;
|
code: (text: string) => string;
|
||||||
codeBlock: (text: string) => string;
|
codeBlock: (text: string) => string;
|
||||||
codeBlockBorder: (text: string) => string;
|
codeBlockBorder: (text: string) => string;
|
||||||
|
|
@ -460,21 +468,10 @@ export interface MarkdownTheme {
|
||||||
quoteBorder: (text: string) => string;
|
quoteBorder: (text: string) => string;
|
||||||
hr: (text: string) => string;
|
hr: (text: string) => string;
|
||||||
listBullet: (text: string) => string;
|
listBullet: (text: string) => string;
|
||||||
}
|
bold: (text: string) => string;
|
||||||
|
italic: (text: string) => string;
|
||||||
export class Markdown {
|
strikethrough: (text: string) => string;
|
||||||
constructor(
|
underline: (text: string) => string;
|
||||||
text: string,
|
|
||||||
paddingX: number,
|
|
||||||
paddingY: number,
|
|
||||||
defaultTextStyle?: DefaultTextStyle,
|
|
||||||
theme?: MarkdownTheme // Optional theme functions
|
|
||||||
)
|
|
||||||
|
|
||||||
// Usage in component
|
|
||||||
renderHeading(text: string) {
|
|
||||||
return this.theme.heading(text); // Applies color
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -490,6 +487,7 @@ function getMarkdownTheme(): MarkdownTheme {
|
||||||
return {
|
return {
|
||||||
heading: (text) => theme.fg('mdHeading', text),
|
heading: (text) => theme.fg('mdHeading', text),
|
||||||
link: (text) => theme.fg('mdLink', text),
|
link: (text) => theme.fg('mdLink', text),
|
||||||
|
linkUrl: (text) => theme.fg('mdLinkUrl', text),
|
||||||
code: (text) => theme.fg('mdCode', text),
|
code: (text) => theme.fg('mdCode', text),
|
||||||
codeBlock: (text) => theme.fg('mdCodeBlock', text),
|
codeBlock: (text) => theme.fg('mdCodeBlock', text),
|
||||||
codeBlockBorder: (text) => theme.fg('mdCodeBlockBorder', text),
|
codeBlockBorder: (text) => theme.fg('mdCodeBlockBorder', text),
|
||||||
|
|
@ -497,6 +495,10 @@ function getMarkdownTheme(): MarkdownTheme {
|
||||||
quoteBorder: (text) => theme.fg('mdQuoteBorder', text),
|
quoteBorder: (text) => theme.fg('mdQuoteBorder', text),
|
||||||
hr: (text) => theme.fg('mdHr', text),
|
hr: (text) => theme.fg('mdHr', text),
|
||||||
listBullet: (text) => theme.fg('mdListBullet', text),
|
listBullet: (text) => theme.fg('mdListBullet', text),
|
||||||
|
bold: (text) => theme.bold(text),
|
||||||
|
italic: (text) => theme.italic(text),
|
||||||
|
underline: (text) => theme.underline(text),
|
||||||
|
strikethrough: (text) => chalk.strikethrough(text),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -530,7 +532,7 @@ theme.bg('toolSuccessBg', output)
|
||||||
|
|
||||||
// Combine styles
|
// Combine styles
|
||||||
theme.bold(theme.fg('accent', 'Title'))
|
theme.bold(theme.fg('accent', 'Title'))
|
||||||
theme.dim(theme.fg('muted', 'metadata'))
|
theme.italic(theme.fg('muted', 'metadata'))
|
||||||
|
|
||||||
// Nested foreground + background
|
// Nested foreground + background
|
||||||
const userMsg = theme.bg('userMessageBg',
|
const userMsg = theme.bg('userMessageBg',
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { AppMessage, Attachment } from "@mariozechner/pi-agent-core";
|
import type { AppMessage, Attachment } from "@mariozechner/pi-agent-core";
|
||||||
|
import type { ToolResultMessage } from "@mariozechner/pi-ai";
|
||||||
import type { SessionEntry } from "../session-manager.js";
|
import type { SessionEntry } from "../session-manager.js";
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -121,7 +122,7 @@ export interface TurnEndEvent {
|
||||||
type: "turn_end";
|
type: "turn_end";
|
||||||
turnIndex: number;
|
turnIndex: number;
|
||||||
message: AppMessage;
|
message: AppMessage;
|
||||||
toolResults: AppMessage[];
|
toolResults: ToolResultMessage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -235,9 +235,9 @@ Guidelines:
|
||||||
${guidelines}
|
${guidelines}
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
- Your own documentation (including custom model setup and theme creation) is at: ${readmePath}
|
- Main documentation: ${readmePath}
|
||||||
- Additional documentation (hooks, themes, RPC, etc.) is in: ${docsPath}
|
- Additional docs: ${docsPath}
|
||||||
- Read it when users ask about features, configuration, or setup, and especially if the user asks you to add a custom model or provider, create a custom theme, or write a hook.`;
|
- When asked about: custom models/providers (README sufficient), themes (docs/theme.md), skills (docs/skills.md), hooks (docs/hooks.md), custom tools (docs/custom-tools.md), RPC (docs/rpc.md)`;
|
||||||
|
|
||||||
if (appendSection) {
|
if (appendSection) {
|
||||||
prompt += appendSection;
|
prompt += appendSection;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue