Six focused features that extend the pi agent's capabilities β URL fetching, editor state management, artifact persistence, structured commit metadata, branded startup, and real-time plan tracking. pi μμ΄μ νΈμ κΈ°λ₯μ νμ₯νλ 6κ°μ μ§μ€ κΈ°λ₯ β URL κ°μ Έμ€κΈ°, μλν° μν κ΄λ¦¬, μν°ν©νΈ μ§μμ±, ꡬ쑰νλ μ»€λ° λ©νλ°μ΄ν°, λΈλλλ μμ νλ©΄, μ€μκ° κ³ν μΆμ .
URL β Markdown conversion tool for agents. Fetches any URL, converts HTML to clean Markdown using Mozilla Readability + Turndown, and caches results for fast repeated access. μμ΄μ νΈλ₯Ό μν URL β Markdown λ³ν λꡬ. λͺ¨λ URLμ κ°μ Έμ Mozilla Readability + TurndownμΌλ‘ HTMLμ κΉλν MarkdownμΌλ‘ λ³ννκ³ , λΉ λ₯Έ λ°λ³΅ μ κ·Όμ μν΄ κ²°κ³Όλ₯Ό μΊμν©λλ€.
| ParameterνλΌλ―Έν° | Typeνμ | Requiredνμ | DefaultκΈ°λ³Έκ° |
|---|---|---|---|
url |
string | Yesμ | β |
raw |
boolean | Noμλμ€ | false |
includeScripts |
boolean | Noμλμ€ | false |
maxLength |
number | Noμλμ€ | β |
In-memory LRU cache. 100 entries max, 15-minute TTL. Cache key is derived from JSON.stringify({url, mode, scripts}) where mode is "full" (default) or "full" when raw is true.
μΈλ©λͺ¨λ¦¬ LRU μΊμ. μ΅λ 100κ° νλͺ©, 15λΆ TTL. μΊμ ν€λ JSON.stringify({url, mode, scripts})μμ νμλ©λλ€. μ¬κΈ°μ modeλ κΈ°λ³Έκ° "auto" λλ rawκ° trueμΌ λ "full"μ
λλ€.
MAX_CONTENT_SIZE = 10 MB
β checked via content-length header and actual byte count
content-length ν€λμ μ€μ λ°μ΄νΈ μλ‘ νμΈ
FETCH_TIMEOUT_MS = 30 s
β hard abort via AbortController
AbortControllerλ₯Ό ν΅ν κ°μ μ€λ¨
| Modeλͺ¨λ | TriggerνΈλ¦¬κ±° | Behaviorλμ |
|---|---|---|
| full | raw: false (default) |
Readable content β Mozilla Readability + Turndown + GFMμ½μ μ μλ μ½ν μΈ β Mozilla Readability + Turndown + GFM |
| raw | raw: true |
Full HTML converted to Markdown via Turndown (no Readability filter)μ 체 HTMLμ TurndownμΌλ‘ Markdown λ³ν (Readability νν° μμ) |
When maxLength is set and content exceeds it, the returned copy is sliced and suffixed with:
maxLengthκ° μ€μ λκ³ μ½ν
μΈ κ° μ΄κ³Όνλ©΄ λ°νλ μ¬λ³Έμ μλ¦¬κ³ λ€μ μ λ―Έμ¬κ° λΆμ΅λλ€:
The original content stored in cache is not truncated. μΊμμ μ μ₯λ μλ³Έ μ½ν μΈ λ μλ₯΄μ§ μμ΅λλ€.
Session-scoped single-slot stash for editor text. Save a snippet, clear the editor, restore it later β all without leaving the editor. μλν° ν μ€νΈλ₯Ό μν μΈμ λ²μμ λ¨μΌ μ¬λ‘― μ€νμ. μ€λν«μ μ μ₯νκ³ , μλν°λ₯Ό μ§μ°κ³ , λμ€μ 볡μ β μλν°λ₯Ό λ λμ§ μκ³ λͺ¨λ κ°λ₯ν©λλ€.
| Commandλͺ λ Ή | Actionλμ |
|---|---|
/stash-save |
Copy current editor text into the stash slotνμ¬ μλν° ν μ€νΈλ₯Ό μ€νμ μ¬λ‘―μ λ³΅μ¬ |
/stash-clear |
Clear the stash slot contentsμ€νμ μ¬λ‘― λ΄μ© μ§μ°κΈ° |
/stash-restore |
Replace editor text with stashed contentμλν° ν μ€νΈλ₯Ό μ€νμλ λ΄μ©μΌλ‘ κ΅μ²΄ |
| Shortcutλ¨μΆν€ | Byteλ°μ΄νΈ | Actionλμ |
|---|---|---|
Ctrl+S |
\x13 |
Save to stashμ€νμμ μ μ₯ |
Ctrl+R |
\x12 |
Restore from stashμ€νμμμ 볡μ |
Ctrl+K |
\x0b |
Clear stashμ€νμ μ§μ°κΈ° |
An editor decorator appends a status line at the bottom of the editor showing stash size and shortcut hints. μλν° λ°μ½λ μ΄ν°κ° μλν° νλ¨μ μ€νμ ν¬κΈ°μ λ¨μΆν€ ννΈλ₯Ό 보μ¬μ£Όλ μν μ€μ μΆκ°ν©λλ€.
Structured per-run artifact directories for subagent outputs. Each subagent invocation gets an isolated directory tree for its output, progress, and declared read files. μλΈμμ΄μ νΈ μΆλ ₯μ μν ꡬ쑰νλ μ€νλ³ μν°ν©νΈ λλ ν 리. κ° μλΈμμ΄μ νΈ νΈμΆμ μΆλ ₯, μ§ν, μ μΈλ μ½κΈ° νμΌμ μν 격리λ λλ ν 리 νΈλ¦¬λ₯Ό κ°μ Έμ΅λλ€.
run.json Schema
run.json μ€ν€λ§
| Field | Typeνμ | Descriptionμ€λͺ |
|---|---|---|
agentName | string | Subagent identifierμλΈμμ΄μ νΈ μλ³μ |
runId | string | Unique run identifierκ³ μ μ€ν μλ³μ |
rootRunId | string | Parent session run identifierλΆλͺ¨ μΈμ μ€ν μλ³μ |
cwd | string | Working directory at creation timeμμ± μμ μ μμ λλ ν 리 |
outputFile | string? | Resolved output pathν΄κ²°λ μΆλ ₯ κ²½λ‘ |
progressFile | string? | Resolved progress pathν΄κ²°λ μ§ν κ²½λ‘ |
readFiles | string[] | Declared read file pathsμ μΈλ μ½κΈ° νμΌ κ²½λ‘ |
createdAt | string | ISO 8601 timestampISO 8601 νμμ€ν¬ν |
All user-supplied paths are validated before resolution: λͺ¨λ μ¬μ©μ μ 곡 κ²½λ‘λ ν΄κ²° μ μ κ²μ¦λ©λλ€:
/etc/passwd)
μ λ κ²½λ‘ κ±°λΆ (/etc/passwd)
~, ~/...)
ν λ¨μΆν€ κ±°λΆ (~, ~/...)
../../etc)
λ° λλ ν 리λ₯Ό λ²μ΄λλ κ²½λ‘ κ±°λΆ (../../etc)
sanitizeSegment() replaces non-alphanumeric characters (except ., _, -) with -, then strips leading and trailing dashes. Falls back to "run" if the result is empty.
sanitizeSegment()μ μμ«μκ° μλ λ¬Έμ(., _, - μ μΈ)λ₯Ό -λ‘ κ΅μ²΄νκ³ , μ ν λ° νν λμλ₯Ό μ κ±°ν©λλ€. κ²°κ³Όκ° λΉμ΄μμΌλ©΄ "run"μ μ¬μ©ν©λλ€.
Structured git trailers that embed decision context directly into commit messages. Future agents and developers can query project knowledge via git log.
μ»€λ° λ©μμ§μ κ²°μ 컨ν
μ€νΈλ₯Ό μ§μ μ½μ
νλ ꡬ쑰νλ git νΈλ μΌλ¬. λ―Έλμ μμ΄μ νΈμ κ°λ°μκ° git logλ₯Ό ν΅ν΄ νλ‘μ νΈ μ§μμ μ‘°νν μ μμ΅λλ€.
| TrailerνΈλ μΌλ¬ | Formatνμ | Exampleμμ |
|---|---|---|
Constraint: |
Free textμμ ν μ€νΈ | Constraint: must support Node 18+ |
Rejected: |
<alt> | <reason> |
Rejected: SQLite | adds native dependency |
Confidence: |
high / medium / lowhigh / medium / low | Confidence: high |
Scope-risk: |
narrow / moderate / broadnarrow / moderate / broad | Scope-risk: narrow |
Reversibility: |
clean / moderate / difficultclean / moderate / difficult | Reversibility: clean |
Directive: |
Free textμμ ν μ€νΈ | Directive: keep backwards compat |
Tested: |
Free textμμ ν μ€νΈ | Tested: manual verification on macOS |
Not-tested: |
Free textμμ ν μ€νΈ | Not-tested: Windows path handling |
Related: |
Free textμμ ν μ€νΈ | Related: #42 |
Filter commits by any trailer key: λͺ¨λ νΈλ μΌλ¬ ν€λ‘ μ»€λ° νν°λ§:
The lore-setup skill writes Lore commit format rules to AGENTS.md or CLAUDE.md so all agents automatically use structured git trailers in commit messages.
lore-setup μ€ν¬μ΄ AGENTS.md λλ CLAUDE.mdμ Lore μ»€λ° νμ κ·μΉμ μμ±νμ¬ λͺ¨λ μμ΄μ νΈκ° μ»€λ° λ©μμ§μ μλμΌλ‘ ꡬ쑰νλ git νΈλ μΌλ¬λ₯Ό μ¬μ©νλλ‘ ν©λλ€.
ROACH PI branded header that replaces the generic pi startup listing. Shows the ASCII art logo and quick-start hints when the session begins. μΌλ°μ μΈ pi μμ λͺ©λ‘μ λ체νλ ROACH PI λΈλλλ ν€λ. μΈμ μμ μ ASCII μνΈ λ‘κ³ μ λΉ λ₯Έ μμ ννΈλ₯Ό νμν©λλ€.
/welcome Command
/welcome λͺ
λ Ή
| Inputμ λ ₯ | Effectν¨κ³Ό |
|---|---|
off, hide, dismiss |
Hide the bannerλ°°λ μ¨κΈ°κΈ° |
on, show, restore |
Show the bannerλ°°λ νμ |
(bare) /welcome |
Toggle visibilityκ°μμ± ν κΈ |
/setup
/setupκ³Όμ μνΈμμ©
/setup sets quietStartup: true so the pi agent's generic startup listing is suppressed, making the ROACH PI banner the main startup surface.
/setupμ΄ quietStartup: trueλ₯Ό μ€μ νμ¬ pi μμ΄μ νΈμ μΌλ°μ μΈ μμ λͺ©λ‘μ΄ μ΅μ λκ³ , ROACH PI λ°°λκ° μ£Ό μμ νλ©΄μ΄ λ©λλ€.
/init
/initκ³Όμ μνΈμμ©
/init also configures banner visibility as part of the initial project setup flow.
/initλ μ΄κΈ° νλ‘μ νΈ μ€μ νλ¦μ μΌλΆλ‘ λ°°λ κ°μμ±μ ꡬμ±ν©λλ€.
Real-time plan and milestone progress displayed in the TUI footer. Shows task completion, running state, and milestone lifecycle at a glance. TUI νΈν°μ νμλλ μ€μκ° κ³ν λ° λ§μΌμ€ν€ μ§ν μν©. μμ μλ£, μ€ν μν, λ§μΌμ€ν€ μλͺ μ£ΌκΈ°λ₯Ό νλμ 보μ¬μ€λλ€.
| Statusμν | Meaningμλ―Έ |
|---|---|
pending | Not yet startedμμ§ μμ μ λ¨ |
running | Currently executingνμ¬ μ€ν μ€ |
completed | Finished successfullyμ±κ³΅μ μΌλ‘ μλ£ |
failed | Finished with errorμ€λ₯λ‘ μλ£ |
| Statusμν | Meaningμλ―Έ |
|---|---|
pending | Waiting to startμμ λκΈ° μ€ |
planning | Plan being draftedκ³ν μμ± μ€ |
executing | Tasks runningμμ μ€ν μ€ |
validating | Review underway리뷰 μ§ν μ€ |
completed | All tasks passedλͺ¨λ μμ ν΅κ³Ό |
failed | Validation failedκ²μ¦ μ€ν¨ |
skipped | Explicitly skippedλͺ μμ μΌλ‘ 건λλ |
A 400ms interval spinner (PLAN_PROGRESS_SPINNER_MS) runs only while tasks are in the running state. Frames cycle through β β β β.
μμ
μ΄ running μνμΈ λμλ§ 400ms κ°κ²© μ€νΌλ(PLAN_PROGRESS_SPINNER_MS)κ° μ€νλ©λλ€. νλ μμ β β β βμ μνν©λλ€.
| File TypeνμΌ μ ν | Patternν¨ν΄ |
|---|---|
| Milestone fileλ§μΌμ€ν€ νμΌ | /(M\d+)-([^/\s]+)\.md$/i |
| State tableμν ν μ΄λΈ | /state.md$/ |
| Todoν μΌ | /todo.md$/ |
| Completionμλ£ | /completion.md$/ |
/reset-phase Command
/reset-phase λͺ
λ Ή
Clears all plan and milestone state from the tracker, returning to a clean slate. νΈλ컀μμ λͺ¨λ κ³ν λ° λ§μΌμ€ν€ μνλ₯Ό μ§μ°κ³ κΉ¨λν μνλ‘ λμκ°λλ€.
The footer subscribes to PlanProgressTracker change notifications via setOnChange(). When progress changes, the footer calls tui.requestRender(true) to update the display. The spinner timer is started on demand and cleaned up in dispose().
νΈν°λ setOnChange()μ ν΅ν΄ PlanProgressTracker λ³κ²½ μλ¦Όμ ꡬλ
ν©λλ€. μ§ν μν©μ΄ λ³κ²½λλ©΄ νΈν°λ tui.requestRender(true)λ₯Ό νΈμΆνμ¬ νμλ₯Ό μ
λ°μ΄νΈν©λλ€. μ€νΌλ νμ΄λ¨Έλ νμν λ μμλκ³ dispose()μμ μ 리λ©λλ€.