feat: add Pi agent blog post, AI tooling, and SVG support
Add new blog post documenting a week using the Pi CLI agent for 100% agentic development. Include AI agent configuration with custom prompts and skills to streamline content creation workflow. - Publish "Week with my-pi-agent" article with Pi logo and screenshot assets - Add .pi/ configuration with new-blog-post prompt and review-article skill - Create AGENTS.md with comprehensive project documentation for AI assistants - Fix SVG rendering to skip unsupported dimension extraction in markdown filter - Update picture generator to handle SVG files with simple img tag - Update syntect dependency to 5.3.0 with default-fancy features - Swap featured segment from older post to new Pi agent article
This commit is contained in:
59
.pi/prompts/new-blog-post.md
Normal file
59
.pi/prompts/new-blog-post.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
description: Create a new blog post with today's date and proper front matter. Takes a title/topic as argument.
|
||||||
|
---
|
||||||
|
Create a new blog post file for this project.
|
||||||
|
|
||||||
|
**Input:** $@ - The title/topic for the blog post
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
1. Generate a URL-friendly slug from the title:
|
||||||
|
- Lowercase
|
||||||
|
- Replace spaces and special characters with hyphens
|
||||||
|
- Remove consecutive hyphens
|
||||||
|
- Strip leading/trailing hyphens
|
||||||
|
|
||||||
|
2. Create the file at `_posts/blog/YYYY-MM-DD-{slug}.md` where YYYY-MM-DD is today's date
|
||||||
|
|
||||||
|
3. Use this front matter template:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
layout: blog
|
||||||
|
title: {Original Title}
|
||||||
|
segments:
|
||||||
|
- blog
|
||||||
|
published: false
|
||||||
|
date: {YYYY-MM-DD}T12:00:00.000Z
|
||||||
|
thumbnail:
|
||||||
|
tags:
|
||||||
|
- News
|
||||||
|
---
|
||||||
|
|
||||||
|
## {First section heading}
|
||||||
|
|
||||||
|
{Leave space for content}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Important:** The date in the filename (YYYY-MM-DD) MUST match the date in the front matter's `date` field
|
||||||
|
|
||||||
|
5. Confirm the file was created with the full path
|
||||||
|
|
||||||
|
## Available Segments
|
||||||
|
- `blog` (default)
|
||||||
|
- `featured`
|
||||||
|
- `broadcasts`
|
||||||
|
- `cookbook`
|
||||||
|
|
||||||
|
## Common Tags
|
||||||
|
- News
|
||||||
|
- Development
|
||||||
|
- Programming
|
||||||
|
- Rust
|
||||||
|
- JavaScript
|
||||||
|
- TypeScript
|
||||||
|
- Keyboards
|
||||||
|
- Tutorial
|
||||||
|
- Personal
|
||||||
98
.pi/skills/review-article/SKILL.md
Normal file
98
.pi/skills/review-article/SKILL.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
name: review-article
|
||||||
|
description: Review blog posts for authenticity, structure, clarity, and improvements while preserving the author's unique voice. Provides suggestions only - no edits.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Article Review Assistant
|
||||||
|
|
||||||
|
You are a thoughtful editorial reviewer who helps the author improve their blog posts while preserving their authentic voice and personal style.
|
||||||
|
|
||||||
|
## Author's Voice Profile
|
||||||
|
|
||||||
|
Based on analysis of previous writing, the author's style includes:
|
||||||
|
|
||||||
|
- **Personal & conversational tone** - Uses first person ("I", "I've"), shares personal experiences and stories
|
||||||
|
- **Authentic storytelling** - Often starts with personal context before diving into technical content
|
||||||
|
- **Strategic emphasis** - Uses **bold** for key concepts and _italics_ for subtle emphasis
|
||||||
|
- **Practical examples** - Includes code snippets, real-world scenarios, actionable takeaways
|
||||||
|
- **Honest vulnerability** - Shares struggles, mistakes, and learning moments openly
|
||||||
|
- **Structured flow** - Uses headers, lists, blockquotes, and code blocks effectively
|
||||||
|
- **Conversational closings** - Often ends with summaries, personal reflections, or invites reader engagement
|
||||||
|
|
||||||
|
## Review Process
|
||||||
|
|
||||||
|
**Input:** Path to a markdown blog post file.
|
||||||
|
|
||||||
|
1. **Read the article** - Understand the full content, message, and intent
|
||||||
|
2. **Analyze against voice profile** - Check for authenticity and consistency
|
||||||
|
3. **Identify improvement opportunities** - Structure, clarity, emphasis, spelling
|
||||||
|
4. **Provide actionable suggestions** - Specific, not vague
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Review Output Format
|
||||||
|
|
||||||
|
### 📋 Article Summary
|
||||||
|
Brief 1-2 sentence summary of what the article is about and its main message.
|
||||||
|
|
||||||
|
### ✅ Strengths
|
||||||
|
What's working well in this article (authentic moments, great explanations, effective structure).
|
||||||
|
|
||||||
|
### 🎯 Topic & Story Fit
|
||||||
|
- Does the topic align with the author's typical subjects (development, personal projects, tutorials, tech insights)?
|
||||||
|
- Does the narrative flow naturally?
|
||||||
|
- Any disconnects between the opening story and the main content?
|
||||||
|
|
||||||
|
### 📝 Structure Suggestions
|
||||||
|
Specific recommendations for:
|
||||||
|
- Header hierarchy and organization
|
||||||
|
- Paragraph flow and transitions
|
||||||
|
- Section ordering or grouping
|
||||||
|
- Opening hook effectiveness
|
||||||
|
- Closing impact
|
||||||
|
|
||||||
|
### 💡 Emphasis Opportunities
|
||||||
|
Suggest specific places where **bold** or _italics_ could strengthen the message:
|
||||||
|
- Key concepts that deserve highlighting
|
||||||
|
- Important takeaways readers should remember
|
||||||
|
- Subtle points that could use gentle emphasis
|
||||||
|
|
||||||
|
### 🔍 Spelling & Grammar
|
||||||
|
List any typos, grammatical issues, or awkward phrasings found (quote the exact text).
|
||||||
|
|
||||||
|
### 🎨 Clarity Improvements
|
||||||
|
- Sentences or paragraphs that could be clearer
|
||||||
|
- Technical terms that need brief explanation
|
||||||
|
- Jargon that might alienate readers
|
||||||
|
- Places where an example would help
|
||||||
|
|
||||||
|
### ⚠️ Authenticity Check
|
||||||
|
- Any moments that feel inauthentic or forced?
|
||||||
|
- Does the voice stay consistent throughout?
|
||||||
|
- Are there places where the author's personality could shine through more?
|
||||||
|
|
||||||
|
### 📌 Suggested Improvements (Without Changing Core Concept)
|
||||||
|
Numbered list of specific, actionable suggestions that:
|
||||||
|
- Enhance clarity without altering meaning
|
||||||
|
- Strengthen the narrative without changing the story
|
||||||
|
- Improve flow without losing the personal touch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Important Guidelines
|
||||||
|
|
||||||
|
- **NEVER make edits** - Only provide suggestions
|
||||||
|
- **Preserve the author's voice** - Don't suggest changes that would make it sound generic
|
||||||
|
- **Be specific** - Quote exact text when suggesting changes
|
||||||
|
- **Explain why** - Give reasoning for each suggestion
|
||||||
|
- **Respect the core message** - Never suggest changes that alter the main concept or story
|
||||||
|
- **Celebrate authenticity** - Highlight moments where the author's genuine voice shines
|
||||||
|
- **Consider the audience** - The blog appears to target developers and tech-curious readers
|
||||||
|
|
||||||
|
## What NOT to Suggest
|
||||||
|
|
||||||
|
- Removing personal anecdotes or stories
|
||||||
|
- Making the tone more "professional" or formal
|
||||||
|
- Generic corporate language
|
||||||
|
- Changes that would alter the fundamental message
|
||||||
|
- Rewriting in a different voice
|
||||||
193
AGENTS.md
Normal file
193
AGENTS.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Personal website and blog hosted at https://michalvanko.dev. A static site generator (SSG) built with Rust using the Axum web framework. During development, content is served via HTTP with SSR; for production, the site is exported to static HTML files using wget crawling.
|
||||||
|
|
||||||
|
**Technology Stack:**
|
||||||
|
- **Backend:** Rust, Axum web framework, Tokio async runtime
|
||||||
|
- **Templating:** Askama (compile-time template engine)
|
||||||
|
- **Styling:** Tailwind CSS v4
|
||||||
|
- **Content:** Markdown with YAML front matter (gray_matter), parsed with pulldown-cmark
|
||||||
|
- **CMS:** Decap CMS (formerly Netlify CMS) for content management
|
||||||
|
- **Build Tool:** Just (command runner, similar to make)
|
||||||
|
- **Deployment:** Caddy reverse proxy, rsync to remote server
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
├── src/ # Rust source code (~40 files, ~2090 lines)
|
||||||
|
│ ├── main.rs # Entry point, sets up Axum server with static file serving
|
||||||
|
│ ├── router.rs # Route definitions and HTTP layer
|
||||||
|
│ ├── pages/ # Page handlers (index, blog, portfolio, etc.)
|
||||||
|
│ ├── blog_posts/ # Blog post model and metadata
|
||||||
|
│ ├── projects/ # Project model and featured projects
|
||||||
|
│ ├── components/ # Reusable UI components (site_header)
|
||||||
|
│ ├── filters/ # Askama template filters (markdown, date, truncate)
|
||||||
|
│ ├── post_utils/ # Post parsing, listing, segments, tags
|
||||||
|
│ ├── picture_generator/ # Responsive image generation (multiple sizes/formats)
|
||||||
|
│ └── feed.rs # RSS feed generation
|
||||||
|
├── templates/ # Askama HTML templates
|
||||||
|
│ ├── base.html # Base template with head, header, footer
|
||||||
|
│ ├── components/ # Reusable template partials
|
||||||
|
│ ├── sections/ # Page section templates
|
||||||
|
│ └── icons/ # SVG icon sprite
|
||||||
|
├── styles/
|
||||||
|
│ ├── input.css # Tailwind source with custom theme
|
||||||
|
│ └── output.css # Generated CSS (gitignored)
|
||||||
|
├── static/ # Static assets served directly
|
||||||
|
│ ├── images/ # Site images
|
||||||
|
│ ├── fonts/ # Custom web fonts (Baloo2)
|
||||||
|
│ ├── svg/ # SVG icons
|
||||||
|
│ └── resources/ # Decap CMS config
|
||||||
|
├── _posts/blog/ # Blog posts (Markdown with front matter)
|
||||||
|
├── _projects/ # Showcase projects (Markdown with front matter)
|
||||||
|
├── _pages/ # Static pages (portfolio.md)
|
||||||
|
├── generated_images/ # Auto-generated responsive images (gitignored)
|
||||||
|
├── dist/ # SSG output folder (gitignored)
|
||||||
|
└── target/ # Rust build artifacts (gitignored)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Entry Points
|
||||||
|
|
||||||
|
- `src/main.rs` - Server startup, static file routing, livereload (debug only)
|
||||||
|
- `src/router.rs` - All route definitions, maps URLs to page handlers
|
||||||
|
- `src/pages/index.rs` - Homepage, demonstrates async data loading pattern
|
||||||
|
|
||||||
|
### Data Flow
|
||||||
|
|
||||||
|
1. **Content Loading:** Markdown files in `_posts/`, `_projects/`, `_pages/` are parsed at runtime
|
||||||
|
2. **Front Matter:** YAML metadata extracted via `gray_matter` crate
|
||||||
|
3. **Template Rendering:** Askama templates receive structs with data
|
||||||
|
4. **Image Generation:** Images auto-generated in multiple sizes on first request
|
||||||
|
5. **SSG Export:** `wget` crawls running server, saves HTML to `dist/`
|
||||||
|
|
||||||
|
## Code Conventions
|
||||||
|
|
||||||
|
### Rust Patterns
|
||||||
|
|
||||||
|
- **Module Organization:** Each domain has a `mod.rs` with submodules
|
||||||
|
- **Async Handlers:** Page handlers use `async fn` returning `Result<impl IntoResponse, StatusCode>`
|
||||||
|
- **Template Structs:** Each page has a corresponding `#[derive(Template)]` struct
|
||||||
|
- **Error Handling:** Uses `anyhow` for errors, `StatusCode` for HTTP responses
|
||||||
|
- **Parallel Loading:** `tokio::try_join!` for concurrent data fetching
|
||||||
|
|
||||||
|
### Template Patterns
|
||||||
|
|
||||||
|
- **Inheritance:** Templates extend `base.html` using `{% block content %}`
|
||||||
|
- **Includes:** Reusable partials via `{% include "component.html" %}`
|
||||||
|
- **Filters:** Custom filters in `src/filters/` (e.g., `{{ content|markdown }}`)
|
||||||
|
- **Configuration:** `askama.toml` sets template directory and whitespace handling
|
||||||
|
|
||||||
|
### Naming Conventions
|
||||||
|
|
||||||
|
- **Files:** snake_case for Rust files, kebab-case for templates
|
||||||
|
- **Routes:** kebab-case URLs (`/blog`, `/showcase/m-logo-svg`)
|
||||||
|
- **Front Matter:** snake_case fields in YAML
|
||||||
|
|
||||||
|
### Configuration Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `Cargo.toml` | Rust dependencies, package metadata |
|
||||||
|
| `askama.toml` | Template directory config |
|
||||||
|
| `.prettierrc` | JS/JSON formatting (trailing commas, 2-space, single quotes) |
|
||||||
|
| `.nvmrc` | Node.js version: `lts/*` |
|
||||||
|
| `.npmrc` | npm config: `engine-strict=true` |
|
||||||
|
| `justfile` | Build commands and deployment scripts |
|
||||||
|
| `renovate.json` | Dependency update automation |
|
||||||
|
| `static/resources/config.yml` | Decap CMS configuration |
|
||||||
|
|
||||||
|
## Setup Requirements
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- **Rust:** Stable toolchain (uses edition 2021)
|
||||||
|
- **Node.js:** LTS version (for Tailwind CSS, Decap CMS)
|
||||||
|
- **Just:** Command runner (`cargo install just` or system package)
|
||||||
|
- **cargo-watch:** For development hot reload (`cargo install cargo-watch`)
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
- `PORT` - Server port (default: 3080)
|
||||||
|
- `RUST_LOG` - Logging level (default: `axum_server=debug,tower_http=debug`)
|
||||||
|
- `TARGET` - Build target mode (used in `just prod`)
|
||||||
|
|
||||||
|
### Development Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Run development server (starts all services in parallel)
|
||||||
|
just dev
|
||||||
|
# This runs: server_dev, tailwind watch, decap_server
|
||||||
|
|
||||||
|
# Or run individually:
|
||||||
|
just server_dev # Rust server with hot reload
|
||||||
|
just tailwind # CSS watch mode
|
||||||
|
just decap_server # Local CMS backend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just test # Run Rust tests
|
||||||
|
just test_watch # Run tests with watch mode
|
||||||
|
just prod # Run server in release mode
|
||||||
|
just export # Generate static site to dist/
|
||||||
|
just deploy # rsync dist/ to remote server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Files
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
- `Cargo.toml` - Rust dependencies (axum, askama, pulldown-cmark, etc.)
|
||||||
|
- `justfile` - All build/dev/deploy commands
|
||||||
|
- `static/resources/config.yml` - Decap CMS collections and fields
|
||||||
|
- `styles/input.css` - Tailwind theme customization (colors, fonts, spacing)
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
|
||||||
|
- `.gitea/workflows/test.yaml` - Runs `cargo test` on push/PR
|
||||||
|
- `.gitea/workflows/release.yaml` - Builds release, runs SSG export, uploads `dist/` artifact
|
||||||
|
|
||||||
|
### Content Structure
|
||||||
|
|
||||||
|
- `_posts/blog/` - Blog posts with YAML front matter (title, segments, published, date, thumbnail, tags)
|
||||||
|
- `_projects/` - Showcase projects (title, displayed, cover_image, link, classification, tags, featured)
|
||||||
|
- `_pages/portfolio.md` - Portfolio page content (work history, education)
|
||||||
|
|
||||||
|
### Key Dependencies
|
||||||
|
|
||||||
|
**Rust:**
|
||||||
|
- `axum` - Web framework
|
||||||
|
- `askama` - Compile-time templates
|
||||||
|
- `pulldown-cmark` - Markdown parsing
|
||||||
|
- `gray_matter` - YAML front matter extraction
|
||||||
|
- `tokio` - Async runtime
|
||||||
|
- `tower-http` - HTTP middleware (tracing, static files)
|
||||||
|
- `tower-livereload` - Development hot reload
|
||||||
|
- `image` - Image processing for responsive images
|
||||||
|
- `syntect` - Syntax highlighting
|
||||||
|
|
||||||
|
**Node.js:**
|
||||||
|
- `tailwindcss` v4 - CSS framework
|
||||||
|
- `@tailwindcss/cli` - Tailwind CLI
|
||||||
|
|
||||||
|
## Notes for Agents
|
||||||
|
|
||||||
|
1. **Template Changes:** Askama templates are compiled into Rust code. After template changes, the project recompiles automatically with `cargo-watch`.
|
||||||
|
|
||||||
|
2. **Adding Routes:** Add handler in `src/pages/`, register in `src/router.rs`, create template in `templates/`.
|
||||||
|
|
||||||
|
3. **Content Model:** All content uses YAML front matter. See `static/resources/config.yml` for field definitions.
|
||||||
|
|
||||||
|
4. **Image Handling:** Images are auto-generated in multiple sizes. The `picture_generator` module creates responsive `<picture>` elements.
|
||||||
|
|
||||||
|
5. **Debug vs Release:** Debug builds include livereload. Release builds are optimized for production.
|
||||||
|
|
||||||
|
6. **SSG Process:** The static site is generated by running the server and crawling with `wget`. All linked content must be discoverable from the homepage.
|
||||||
@@ -22,7 +22,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
syntect = "5.2.0"
|
syntect = { version = "5.3.0", default-features = false, features = ["default-fancy"] }
|
||||||
indoc = "2.0.5"
|
indoc = "2.0.5"
|
||||||
askama_escape = "0.15.0"
|
askama_escape = "0.15.0"
|
||||||
mime_guess = "2.0.5"
|
mime_guess = "2.0.5"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ layout: blog
|
|||||||
title: Error handling with Either<Type>
|
title: Error handling with Either<Type>
|
||||||
segments:
|
segments:
|
||||||
- blog
|
- blog
|
||||||
- featured
|
|
||||||
published: true
|
published: true
|
||||||
date: 2022-02-28T11:30:54.195Z
|
date: 2022-02-28T11:30:54.195Z
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
91
_posts/blog/2026-04-01-week-with-my-pi-agent.md
Normal file
91
_posts/blog/2026-04-01-week-with-my-pi-agent.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
---
|
||||||
|
layout: blog
|
||||||
|
title: Week with my-pi-agent
|
||||||
|
segments:
|
||||||
|
- blog
|
||||||
|
- featured
|
||||||
|
published: true
|
||||||
|
date: 2026-04-01T12:00:00.000Z
|
||||||
|
thumbnail: /images/uploads/pi-logo.svg
|
||||||
|
tags:
|
||||||
|
- News
|
||||||
|
- AI
|
||||||
|
- Agents
|
||||||
|
- Development
|
||||||
|
---
|
||||||
|
|
||||||
|
Last week I've set a goal for myself to go 100% without writing a single line of code manually. I've been trying agentic workflows for a year now. My first agentic tool I've tried was [aider](https://aider.chat/) and it was pretty cool experience at that time. For the last few months I've been using [OpenCode](https://opencode.ai/) but I haven't been able to let it control 100% of my results. Mainly because it hasn't been able to earn my trust. I've been watching different tools for a long time and decided that it was time to try out something minimal. Something that I can make work for me. Make it work with my workflows and tools I use during work.
|
||||||
|
|
||||||
|
## Meet Pi
|
||||||
|
|
||||||
|
<!--  -->
|
||||||
|
<figure>
|
||||||
|
<img src="/images/uploads/pi-logo.svg" alt="Pi agent logo" class="max-w-[280px] h-[280px] bg-black">
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
[Pi](https://pi.dev) is a **bare bones CLI agent** similar to Claude Code, Codex CLI and OpenCode.
|
||||||
|
Pi itself is very simple. It might be a turnoff for anyone who wants to just download and start using it. You have to spend some time tinkering it.
|
||||||
|
There is a lot of [packages](https://pi.dev/packages), that can bring the functionality of other CLIs to Pi.
|
||||||
|
The community around Pi is very fresh and thriving. We are still in the early adopters era of agentic programming. I'd consider every **package as a potential threat** and **cautiously review** them before installing.
|
||||||
|
|
||||||
|
I discovered Pi when [OpenClaw](https://openclaw.ai/) was released. I was curious about what is powering _OpenClaw_. Back then I wasn't really interested in Pi.
|
||||||
|
But after few weeks with [OpenCode](https://opencode.ai/), I wasn't feeling like the tool is working with my workflow.
|
||||||
|
After trying out Pi I got hooked immediately when I prompted it to generate a custom plugin that is customized to my workflow and environment.
|
||||||
|
I use a nerdish Desktop environment:
|
||||||
|
- [Fedora Linux](https://fedoraproject.org/)
|
||||||
|
- [Noctalia shell](https://noctalia.dev/)
|
||||||
|
- [Niri Window manager](https://niri-wm.github.io/niri/) (special kind of tiling window manager)
|
||||||
|
- [fish](https://fishshell.com/) as a shell
|
||||||
|
- [ZelliJ](https://zellij.dev/) as a terminal multiplexer
|
||||||
|
|
||||||
|
I don't know anyone who uses the same tools I do.
|
||||||
|
|
||||||
|
Other agentic CLIs are like taxi cars, you hop-in, you can tell the driver where you want to go. But it is out of your hands how you get there. You are often restricted in the capabilities of the CLI.
|
||||||
|
The features you leverage right now can be pulled out whenever the author of the CLI consider them not useful. With Pi you can **inspect every single line of code**. Why, and what gets executed and when.
|
||||||
|
With Pi, you build your own ride. Do you need to just get some mail from post office? You build a bicycle. Do you need a team of X "engineers", feel free to burn your tokens however you like - build an airplane.
|
||||||
|
Want to go the to moon? Build yourself a rocketship. There are no limits.
|
||||||
|
|
||||||
|
With no other CLI agent I was ever **motivated to create my own plugins, commands, workflows**. I was always trying to just search for stuff that "just works", but it never worked for me.
|
||||||
|
|
||||||
|
First plugin I've created was that I wanted to have a [`/commit` command](https://github.com/michalvankodev/my-pi-agent/blob/main/agent/extensions/commit.ts).
|
||||||
|
|
||||||
|
- This command should not do `git commit` for me.
|
||||||
|
- It should just generate a commit message and open an editor in a new _ZelliJ_ pane.
|
||||||
|
- I can not only review but edit if I am not satisfied with the output. I can even cancel the commit if I opt to.
|
||||||
|
|
||||||
|
One, two prompts and voilà - I have my first custom plugin. Nothing ground-breaking but it is working just how I like it.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## What works for me
|
||||||
|
|
||||||
|
In my experience a simple approach turned out to have the best results considering getting stuff done, cheaper and reliable.
|
||||||
|
I've tried to set up interactive sub-agents that talk between each other and I was stunned for a moment.
|
||||||
|
After few minutes the output of 4 agents working together was very little and I almost ran out of available tokens.
|
||||||
|
Then I continued with just one main agent and it was able to finish whole task much quicker.
|
||||||
|
The main workflow for me (for backend tasks) is:
|
||||||
|
1. Prompt agent with what are we going to do. "Gather information about existing code". Write a specification file and split work into tasks.
|
||||||
|
We are going to update the specification after each task gets done.
|
||||||
|
2. [`/clarify`](https://github.com/michalvankodev/my-pi-agent/blob/main/agent/prompts/clarify.md) This is the **most powerful prompt** in my workflow. It asks agent to ask clarifying questions. This prevents the agent to invent wheels that already exists or rail off from what we want to accomplish.
|
||||||
|
3. Start working on tasks one by one
|
||||||
|
|
||||||
|
When the context-window gets too big, there is a decision to make. With `/tree` command you can traverse your conversation to a point (after the 2nd step for example) where the agent has enough context about all the tasks that you can continue without starting with fresh context window. Or you can create a `/new` session and prompt it to gather information about the tasks with the link to the spec.
|
||||||
|
|
||||||
|
`/tree` is very useful feature. I use it to fork my current session into multiple new ones and you can parallelize your work (I don't recommend it every time).
|
||||||
|
|
||||||
|
Two other features I use constantly:
|
||||||
|
- Steering - When you see the agent doing something you want to immediately fix, you steer it. Your message
|
||||||
|
arrives as soon as the current tool call finishes.
|
||||||
|
- Follow up - When you want to tell the agent something or request additional work, you follow up. That
|
||||||
|
message gets queued after the agent completes all pending work, instead of waiting for your next prompt.
|
||||||
|
|
||||||
|
There's still more to learn. This is just the experience I've had with Pi during the last week.
|
||||||
|
|
||||||
|
For front-end task I'd choose a different workflow. I'd incorporate `agent-browser` into the loop. Having constant feedback loop is very powerful and allows the agent to run for longer time (do more without constant supervision)
|
||||||
|
|
||||||
|
Another very good use experience I had was with debugging memory issues. This is a task that if you don't do very often during development, but from time to time it happens that unexpected errors happen due to different resource availability on production systems. I've said to the agent what happens and what I think was the issue (I was way way off).
|
||||||
|
It created multiple testing scenario applications in `/tmp` directory to just test off hypothesis.
|
||||||
|
He dug out every single call and investigated deep hierarchy of code deep down to every single dependency in the chain.
|
||||||
|
We haven't been able to find the issue there. So I've used [`heaptrack`](https://github.com/KDE/heaptrack) to provide actual information about the memory allocations and then I just passed the output to the agent. It just came out with the actual issue and provided fix in few seconds.
|
||||||
|
|
||||||
|
It is able to create `bash` commands and execute them in a loop until it discovers significant information. It does so at such velocity that I have to admit I can't imagine now working without it. Once you experience this kind of boost it's unthinkable to go back.
|
||||||
@@ -64,6 +64,19 @@ pub fn parse_markdown<T: fmt::Display>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle SVG files - don't try to get dimensions (image crate doesn't support SVG)
|
||||||
|
if dest_url.to_lowercase().ends_with(".svg") {
|
||||||
|
return Event::Html(
|
||||||
|
formatdoc!(
|
||||||
|
r#"<figure>
|
||||||
|
<img src="{dest_url}" alt="{title}">
|
||||||
|
<figcaption>
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let dev_only_img_path =
|
let dev_only_img_path =
|
||||||
Path::new("static/").join(dest_url.strip_prefix("/").unwrap_or(&dest_url));
|
Path::new("static/").join(dest_url.strip_prefix("/").unwrap_or(&dest_url));
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,27 @@ pub fn generate_picture_markup(
|
|||||||
class_name: Option<&str>,
|
class_name: Option<&str>,
|
||||||
) -> Result<String, anyhow::Error> {
|
) -> Result<String, anyhow::Error> {
|
||||||
let orig_path = Path::new(orig_img_path);
|
let orig_path = Path::new(orig_img_path);
|
||||||
let exported_formats = get_export_formats(orig_path);
|
|
||||||
let class_attr = if let Some(class) = class_name {
|
let class_attr = if let Some(class) = class_name {
|
||||||
format!(r#"class="{class}""#)
|
format!(r#"class="{class}""#)
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle SVG files - return simple img tag with provided dimensions for display sizing
|
||||||
|
if orig_img_path.to_lowercase().ends_with(".svg") {
|
||||||
|
return Ok(formatdoc!(
|
||||||
|
r#"<img
|
||||||
|
src="{orig_img_path}"
|
||||||
|
width="{width}"
|
||||||
|
height="{height}"
|
||||||
|
{class_attr}
|
||||||
|
alt="{alt_text}"
|
||||||
|
>"#
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let exported_formats = get_export_formats(orig_path);
|
||||||
|
|
||||||
// Here the resolution is already correct
|
// Here the resolution is already correct
|
||||||
if exported_formats.is_empty() {
|
if exported_formats.is_empty() {
|
||||||
return Ok(formatdoc!(
|
return Ok(formatdoc!(
|
||||||
|
|||||||
22
static/images/uploads/pi-logo.svg
Normal file
22
static/images/uploads/pi-logo.svg
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
|
||||||
|
<!-- P shape: outer boundary clockwise, inner hole counter-clockwise -->
|
||||||
|
<path fill="#fff" fill-rule="evenodd" d="
|
||||||
|
M165.29 165.29
|
||||||
|
H517.36
|
||||||
|
V400
|
||||||
|
H400
|
||||||
|
V517.36
|
||||||
|
H282.65
|
||||||
|
V634.72
|
||||||
|
H165.29
|
||||||
|
Z
|
||||||
|
M282.65 282.65
|
||||||
|
V400
|
||||||
|
H400
|
||||||
|
V282.65
|
||||||
|
Z
|
||||||
|
"/>
|
||||||
|
<!-- i dot -->
|
||||||
|
<path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 473 B |
BIN
static/images/uploads/pi-screenshot.png
Normal file
BIN
static/images/uploads/pi-screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
@@ -29,6 +29,7 @@
|
|||||||
--color-slate-600: oklch(44.6% 0.043 257.281);
|
--color-slate-600: oklch(44.6% 0.043 257.281);
|
||||||
--color-slate-800: oklch(27.9% 0.041 260.031);
|
--color-slate-800: oklch(27.9% 0.041 260.031);
|
||||||
--color-slate-950: oklch(12.9% 0.042 264.695);
|
--color-slate-950: oklch(12.9% 0.042 264.695);
|
||||||
|
--color-black: #000;
|
||||||
--color-white: #fff;
|
--color-white: #fff;
|
||||||
--spacing: 0.25rem;
|
--spacing: 0.25rem;
|
||||||
--text-sm: 0.875rem;
|
--text-sm: 0.875rem;
|
||||||
@@ -290,6 +291,9 @@
|
|||||||
.m-10 {
|
.m-10 {
|
||||||
margin: calc(var(--spacing) * 10);
|
margin: calc(var(--spacing) * 10);
|
||||||
}
|
}
|
||||||
|
.mx-0 {
|
||||||
|
margin-inline: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.mx-0\.5 {
|
.mx-0\.5 {
|
||||||
margin-inline: calc(var(--spacing) * 0.5);
|
margin-inline: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -389,6 +393,9 @@
|
|||||||
.h-\[240px\] {
|
.h-\[240px\] {
|
||||||
height: 240px;
|
height: 240px;
|
||||||
}
|
}
|
||||||
|
.h-\[280px\] {
|
||||||
|
height: 280px;
|
||||||
|
}
|
||||||
.h-\[320px\] {
|
.h-\[320px\] {
|
||||||
height: 320px;
|
height: 320px;
|
||||||
}
|
}
|
||||||
@@ -425,6 +432,9 @@
|
|||||||
.max-w-\[32rem\] {
|
.max-w-\[32rem\] {
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
}
|
}
|
||||||
|
.max-w-\[280px\] {
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
.max-w-\[392px\] {
|
.max-w-\[392px\] {
|
||||||
max-width: 392px;
|
max-width: 392px;
|
||||||
}
|
}
|
||||||
@@ -437,12 +447,25 @@
|
|||||||
.flex-1 {
|
.flex-1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.flex-shrink {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
.shrink-0 {
|
.shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
.flex-grow {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
.grow {
|
.grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.-translate-y-1 {
|
||||||
|
--tw-translate-y: calc(var(--spacing) * -1);
|
||||||
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
|
}
|
||||||
.-translate-y-1\.5 {
|
.-translate-y-1\.5 {
|
||||||
--tw-translate-y: calc(var(--spacing) * -1.5);
|
--tw-translate-y: calc(var(--spacing) * -1.5);
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
@@ -450,6 +473,9 @@
|
|||||||
.transform {
|
.transform {
|
||||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
||||||
}
|
}
|
||||||
|
.resize {
|
||||||
|
resize: both;
|
||||||
|
}
|
||||||
.break-inside-avoid {
|
.break-inside-avoid {
|
||||||
break-inside: avoid;
|
break-inside: avoid;
|
||||||
}
|
}
|
||||||
@@ -543,6 +569,9 @@
|
|||||||
.border-slate-300 {
|
.border-slate-300 {
|
||||||
border-color: var(--color-slate-300);
|
border-color: var(--color-slate-300);
|
||||||
}
|
}
|
||||||
|
.bg-black {
|
||||||
|
background-color: var(--color-black);
|
||||||
|
}
|
||||||
.bg-blue-50 {
|
.bg-blue-50 {
|
||||||
background-color: var(--color-blue-50);
|
background-color: var(--color-blue-50);
|
||||||
}
|
}
|
||||||
@@ -564,6 +593,9 @@
|
|||||||
.object-cover {
|
.object-cover {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
.p-0 {
|
||||||
|
padding: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.p-0\.5 {
|
.p-0\.5 {
|
||||||
padding: calc(var(--spacing) * 0.5);
|
padding: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -693,6 +725,13 @@
|
|||||||
.no-underline {
|
.no-underline {
|
||||||
text-decoration-line: none;
|
text-decoration-line: none;
|
||||||
}
|
}
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
.outline {
|
||||||
|
outline-style: var(--tw-outline-style);
|
||||||
|
outline-width: 1px;
|
||||||
|
}
|
||||||
.blur {
|
.blur {
|
||||||
--tw-blur: blur(8px);
|
--tw-blur: blur(8px);
|
||||||
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||||
@@ -1649,6 +1688,11 @@ article a {
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-outline-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
@property --tw-blur {
|
@property --tw-blur {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1791,6 +1835,7 @@ article a {
|
|||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
--tw-leading: initial;
|
--tw-leading: initial;
|
||||||
--tw-font-weight: initial;
|
--tw-font-weight: initial;
|
||||||
|
--tw-outline-style: solid;
|
||||||
--tw-blur: initial;
|
--tw-blur: initial;
|
||||||
--tw-brightness: initial;
|
--tw-brightness: initial;
|
||||||
--tw-contrast: initial;
|
--tw-contrast: initial;
|
||||||
|
|||||||
Reference in New Issue
Block a user