diff --git a/bot-templates/Researcher b/bot-templates/Researcher new file mode 100755 index 0000000..cc1b74a --- /dev/null +++ b/bot-templates/Researcher @@ -0,0 +1,146 @@ +#!/bin/bash +# Researcher - Centralized code exploration and query answering bot +# Usage: ./bot-templates/Researcher [recycle-threshold] +# +# Spawns one Researcher per worktree. Workers send QUERY_REQUEST; Researcher +# answers from L1/L2/L3 cache and replies with QUERY_RESPONSE. + +set -e + +if [ $# -lt 2 ]; then + echo "Usage: $0 [recycle-threshold]" + echo " backend: claude, kiro-cli" + echo " recycle-threshold: recycle after N queries (default: 50)" + exit 1 +fi + +BACKEND="$1" +WORKDIR="$2" +RECYCLE_THRESHOLD="${3:-50}" + +ALIAS_NAME="researcher" + +NAMESPACE=$(namespace) +if [ -z "$NAMESPACE" ]; then + echo "Error: No namespace found. Is anvillm running?" + exit 1 +fi + +AGENT_MOUNT="agent" + +echo "Creating researcher session..." +echo "new $BACKEND $WORKDIR" | 9p write $AGENT_MOUNT/ctl +RESEARCHER_ID=$(9p read $AGENT_MOUNT/list | head -1 | awk '{print $1}') + +echo "$ALIAS_NAME" | 9p write $AGENT_MOUNT/$RESEARCHER_ID/alias + +cat <" ~/doc/agent-kb/ + +Read all relevant entries in full. If KB provides a complete answer: + - Reply with Cache: L2 + - Increment query counter + +### L3 — Code / Web Exploration (cache miss) + +Only on L1 and L2 miss: explore the codebase or search the web. + + - Use Glob, Grep, Read for code exploration + - Use WebSearch / WebFetch for external documentation + - Write back to agent-kb immediately after any significant discovery + +Write-back format: use the agent-kb skill (denote naming, frontmatter with title/date/tags/identifier/verified/source). + +After write-back, reply with Cache: L3. Increment query counter. + +## QUERY_RESPONSE Format + +Reply to the requester's agent ID using: + + send_message: + from: $RESEARCHER_ID + to: + type: QUERY_RESPONSE + subject: Re: + body: + Answer: + Sources: + Cache: L1 | L2 | L3 + +## Sequential Processing + +Handle one query at a time. If multiple messages arrive, process them in order. Do not attempt parallel query resolution. + +## KB Protocol + +Before answering any query, search the knowledge base: + + grep -ril "" ~/doc/agent-kb/ + +Rules: +1. On session start: search KB with keywords from the first query. Read all relevant hits. +2. Before ANY file exploration: check KB first. If KB has the answer, use it directly. +3. After any significant discovery: write a KB entry immediately. +4. Prefer specific, verifiable answers. Cite sources. + +Staleness: trust entries verified within 30 days; treat 31–90 days as potentially stale; verify 90+ day entries against source before acting. + +## Idle Loop + +After sending each QUERY_RESPONSE: +1. Increment your internal query counter +2. If counter >= $RECYCLE_THRESHOLD: send RECYCLE_REQUEST and stop +3. Otherwise: set state to idle and wait for the next message (~15s wakeup) +EOF + +echo "" +echo "✓ Researcher ready" +echo "" +echo "Session: $RESEARCHER_ID (alias: $ALIAS_NAME)" +echo "Recycle threshold: $RECYCLE_THRESHOLD queries" +echo "" +echo "Workers send QUERY_REQUEST to session ID: $RESEARCHER_ID" diff --git a/cfg/roles/default.yaml b/cfg/roles/default.yaml index 1d92d86..787a98b 100644 --- a/cfg/roles/default.yaml +++ b/cfg/roles/default.yaml @@ -49,7 +49,7 @@ filesystem: - "{HOME}/.yarnrc.yml" - "{HOME}/.npmrc" - "{HOME}/.ansible/tmp" - - "{XDG_RUNTIME_DIR}/podman" + - "{XDG_RUNTIME_DIR}" - "{XDG_DATA_HOME}/containers" - "{XDG_CONFIG_HOME}/containers" - "{XDG_CONFIG_HOME}/pip" diff --git a/cmd/anvilmcp/execute.go b/cmd/anvilmcp/execute.go index 175b116..b327a24 100644 --- a/cmd/anvilmcp/execute.go +++ b/cmd/anvilmcp/execute.go @@ -175,10 +175,33 @@ func executeCode(code, language string, timeout int) (string, error) { "--ro", "/etc/alternatives", "--ro", "/etc/ld.so.cache", "--rw", namespace, + "--unrestricted-network", + } + + // Add common user binary directories + userBinDirs := []string{ + filepath.Join(homeDir, "bin"), + filepath.Join(homeDir, ".local", "bin"), + filepath.Join(homeDir, "opt"), + filepath.Join(homeDir, "go", "bin"), + } + + // Add PLAN9 bin if set + if plan9 := os.Getenv("PLAN9"); plan9 != "" { + userBinDirs = append(userBinDirs, filepath.Join(plan9, "bin")) + } + + for _, dir := range userBinDirs { + if _, err := os.Stat(dir); err == nil { + args = append(args, "--rox", dir) + } + } + + args = append(args, "--env", "NAMESPACE=" + namespace, "--env", "PATH=/usr/bin:/bin", "--env", "HOME=" + homeDir, - } + ) if agentID != "" { args = append(args, "--env", "AGENT_ID="+agentID) } diff --git a/mcptools/github-to-beads b/mcptools/github-to-beads new file mode 100755 index 0000000..ab8b914 --- /dev/null +++ b/mcptools/github-to-beads @@ -0,0 +1,65 @@ +#!/bin/bash +# capabilities: tasks, github +# description: Import GitHub issue into beads: github-to-beads OWNER/REPO ISSUE_NUMBER +set -euo pipefail + +repo="${1:?Usage: github-to-beads OWNER/REPO ISSUE_NUMBER}" +issue="${2:?Usage: github-to-beads OWNER/REPO ISSUE_NUMBER}" + +# Check if already imported +if 9p read agent/beads/list | jq -e ".[] | select(.title | contains(\"#$issue\"))" >/dev/null 2>&1; then + echo "Issue #$issue already imported" >&2 + exit 0 +fi + +# Fetch issue data +data=$(gh issue view "$issue" --repo "$repo" --json number,title,body,state,labels 2>/dev/null) + +number=$(echo "$data" | jq -r '.number') +title=$(echo "$data" | jq -r '.title') +body=$(echo "$data" | jq -r '.body // empty') +state=$(echo "$data" | jq -r '.state') +labels=$(echo "$data" | jq -r '.labels[].name' | tr '\n' ' ') + +# Determine issue type from labels +issue_type="task" +if echo "$labels" | grep -qi "bug"; then + issue_type="bug" +fi + +# Determine status +status="open" +if [[ "$state" == "CLOSED" ]]; then + status="closed" +fi + +# Build title: #NUMBER: title +bead_title="#$number: $title" + +# Create parent bead +echo "new \"$bead_title\" \"$body\"" | 9p write agent/beads/ctl + +# Get created bead ID +bead_id=$(9p read agent/beads/list | jq -r ".[] | select(.title | contains(\"#$number\")) | .id" | head -1) + +# Update issue type if not task +if [[ "$issue_type" != "task" ]]; then + echo "update $bead_id issue_type $issue_type" | 9p write agent/beads/ctl +fi + +# Update status if closed +if [[ "$status" == "closed" ]]; then + echo "update $bead_id status closed" | 9p write agent/beads/ctl +fi + +# Parse task list from body +if [[ -n "$body" ]]; then + # Extract unchecked tasks: - [ ] Task name + echo "$body" | grep -E '^\s*-\s+\[\s+\]' | sed -E 's/^\s*-\s+\[\s+\]\s*//' | while IFS= read -r task; do + if [[ -n "$task" ]]; then + echo "new \"$task\" \"\" $bead_id" | 9p write agent/beads/ctl + fi + done +fi + +echo "$bead_id" diff --git a/mcptools/jira-to-beads b/mcptools/jira-to-beads new file mode 100755 index 0000000..a1580b1 --- /dev/null +++ b/mcptools/jira-to-beads @@ -0,0 +1,71 @@ +#!/bin/bash +# capabilities: tasks, jira +# description: Import Jira ticket hierarchy into beads: jira-to-beads PROJ-12345 +set -euo pipefail + +ticket="${1:?Usage: jira-to-beads TICKET-KEY}" + +# Check if already imported +if 9p read agent/beads/list | jq -e ".[] | select(.title | contains(\"$ticket\"))" >/dev/null 2>&1; then + echo "Ticket $ticket already imported" >&2 + exit 0 +fi + +# Find root ticket (walk up parent chain) +find_root() { + local key="$1" + local parent + parent=$(jira issue view "$key" --raw 2>/dev/null | jq -r '.fields.parent.key // empty') + if [[ -n "$parent" ]]; then + find_root "$parent" + else + echo "$key" + fi +} + +# Create bead from ticket +create_bead() { + local key="$1" + local parent_bead="${2:-}" + + # Fetch ticket data + local data + data=$(jira issue view "$key" --raw 2>/dev/null) + + local summary + summary=$(echo "$data" | jq -r '.fields.summary') + + local description + description=$(echo "$data" | jq -r '.fields.description // empty') + + # Build title: KEY: summary + local title="$key: $summary" + + # Create bead + if [[ -n "$parent_bead" ]]; then + echo "new \"$title\" \"$description\" $parent_bead" | 9p write agent/beads/ctl + else + echo "new \"$title\" \"$description\"" | 9p write agent/beads/ctl + fi + + # Get created bead ID + local bead_id + bead_id=$(9p read agent/beads/list | jq -r ".[] | select(.title | contains(\"$key\")) | .id" | head -1) + + # Process children + local children + children=$(jira issue list --parent "$key" --plain --no-truncate 2>/dev/null | tail -n +2 | awk '{print $1}' || true) + + if [[ -n "$children" ]]; then + while IFS= read -r child; do + [[ -n "$child" ]] && create_bead "$child" "$bead_id" + done <<< "$children" + fi + + echo "$bead_id" +} + +# Start import from root +root=$(find_root "$ticket") +echo "Importing from root: $root" >&2 +create_bead "$root" diff --git a/skills/acme-api/README.md b/skills/acme-api/README.md deleted file mode 100644 index cdb5345..0000000 --- a/skills/acme-api/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Acme 9P API Skill - -This skill provides comprehensive guidance for programming the acme text editor's 9P file interface in any programming language. - -## What This Skill Does - -The acme-api skill helps you write code that interacts with acme windows through the 9P filesystem interface. It provides: - -- Complete reference for all acme files (ctl, event, body, addr, etc.) -- Event protocol parsing and handling -- Code examples in multiple languages (Go, Python, C, Shell) -- Quick reference for common operations -- Language-agnostic guidance (works with any 9P client) - -## When It's Used - -This skill is automatically invoked by Claude when: -- Writing code to control acme windows -- Handling acme events -- Manipulating text in acme programmatically -- Integrating tools with acme - -You can also manually invoke it with `/acme-api` - -## Files in This Skill - -- **SKILL.md** - Main skill file with overview and quick start -- **file-reference.md** - Complete reference for all acme files -- **event-protocol.md** - Event format, parsing, and handling patterns -- **examples.md** - Code examples in multiple languages -- **quick-reference.md** - Fast lookup for common operations - -## Structure - -The skill is organized to provide: - -1. **Quick start** in SKILL.md for common patterns -2. **Detailed references** in supporting files -3. **Working code examples** in multiple languages -4. **Quick lookup** for experienced users - -## Topics Covered - -### File Operations -- Creating windows (`new/ctl`) -- Control commands (`ctl`) -- Text addressing (`addr`) -- Reading/writing text (`body`, `data`, `xdata`) -- Tag manipulation (`tag`) - -### Event Handling -- Event structure (binary format) -- Event types (Execute, Look, Insert, Delete) -- Event parsing in multiple languages -- Acknowledgement patterns -- Common event handling patterns - -### Programming Languages -- **Go**: With 9P client or direct file operations -- **Python**: Using struct and os modules -- **C**: Direct system calls -- **Shell**: Using 9p command-line tool -- **Any language**: Via standard file I/O - -## Usage Examples - -### Creating a Window -```python -with open('/mnt/acme/new/ctl', 'r') as f: - winid = int(f.read().strip()) -``` - -### Handling Events -```python -event = read_event(fd) -if event.c2 == 'X': # Execute command - handle_execute(event.text) -write_event(fd, event) # Acknowledge -``` - -### Text Manipulation -```python -with open(f'/mnt/acme/{winid}/addr', 'w') as f: - f.write('0,$') # Select all -with open(f'/mnt/acme/{winid}/data', 'w') as f: - f.write('new content') # Replace -``` - -## References - -- Plan 9 acme(4) man page -- Russ Cox's "Acme: A User Interface for Programmers" -- Plan 9 from User Space documentation - -## Version - -1.0.0 - Initial release with comprehensive API coverage diff --git a/skills/acme-api/SKILL.md b/skills/acme-api/SKILL.md index a623b65..7896ba2 100644 --- a/skills/acme-api/SKILL.md +++ b/skills/acme-api/SKILL.md @@ -5,224 +5,81 @@ description: Programming the acme text editor 9P API. Use when writing code to c version: 1.1.0 --- -# Acme 9P API Programming +# Acme 9P API (plan9port) -This skill provides comprehensive guidance for programming against the acme text editor's 9P file interface, enabling you to create tools and scripts that interact with acme windows in any language with a 9P client. +Control acme via 9P. Use `9p read/write acme/...` -## Overview - -Acme exposes its functionality through a 9P file server. On plan9port (Plan 9 from User Space), you access this via the `9p` command-line tool. On native Plan 9, acme is typically mounted at `/mnt/acme`. - -**This skill focuses on plan9port**, which is the most common deployment. Where behavior differs, native Plan 9 specifics are noted. - -### Accessing Acme's Namespace - -**plan9port** (recommended): -- Use `9p ls acme` to list files -- Use `9p read acme/path` to read -- Use `9p write acme/path` or `echo data | 9p write acme/path` to write - -**Native Plan 9**: -- Direct filesystem access at `/mnt/acme` -- Use standard file operations - -### Window File Hierarchy +## Files ``` acme/ -├── index # List of all windows -├── new/ # Create new windows -│ └── ctl # Read to create window and get ID -└── $winid/ # Per-window directory (e.g., acme/5/) - ├── addr # Set/query text addresses - ├── body # Window body content - ├── ctl # Control commands - ├── data # Read/write at current address - ├── errors # Error messages - ├── event # Event stream - ├── tag # Window tag content - └── xdata # Read without address advance +├── cons # command stdout/stderr +├── index # all windows: id tag_len body_len isdir dirty tag (fields @0,12,24,36,48,60) +├── log # operations (blocks): id op name (ops: new,zerox,get,put,del) +├── new/ctl # read returns new window id +└── $id/ + ├── addr # set/query addresses (write addr, read #m,#n char offsets) + ├── body # content (read any offset, write appends) + ├── ctl # read: 10 fields (id tag_len body_len isdir dirty width font tabwidth undo redo) + │ # write: commands (see below) + ├── data # read/write at addr, advances to end + ├── errors # append to dir/+Errors + ├── event # event stream (see protocol) + ├── tag # tag content (read any offset, write appends) + └── xdata # like data but stops at end, no advance ``` -## Quick Start +## ctl Commands -### Basic Window Control Pattern +`addr=dot` `clean` `dirty` `cleartag` `del` `delete` `dot=addr` `dump cmd` `dumpdir /path` `get` `put` `font /path` `limit=addr` `mark` `nomark` `name /path` `show` -1. **Create or attach to window**: Read window ID from `new/ctl` or parse `index` -2. **Set up event handling**: Open `event` for reading -3. **Control the window**: Write commands to `ctl` -4. **Manipulate text**: Use `addr` to set position, `data` to read/write -5. **Process events**: Read from `event` in a loop +## addr Syntax -### Common Operations - -**Create a new window:** -```bash -winid=$(9p read acme/new/ctl | awk '{print $1}') -# Use $winid for all subsequent operations -``` - -**Execute a command:** -```bash -echo "clean" | 9p write acme/$winid/ctl -echo "show" | 9p write acme/$winid/ctl -echo "name /path/to/file" | 9p write acme/$winid/ctl -``` - -**Set text address:** -```bash -echo "0" | 9p write acme/$winid/addr # Start of file -echo "\$" | 9p write acme/$winid/addr # End of file -echo "0,\$" | 9p write acme/$winid/addr # Entire file -9p read acme/$winid/addr # Get resolved positions (q0 q1) -``` - -**Read/write text:** -```bash -# Write to body (replaces all) -echo "New content" | 9p write acme/$winid/body - -# Read entire body -9p read acme/$winid/body - -# Append to end using addr + data -echo "\$" | 9p write acme/$winid/addr -echo "appended text" | 9p write acme/$winid/data -``` - -**Handle events:** -``` -Read acme/$winid/event in a loop -Each event is 5×rune(4bytes) + type(1byte) + text(variable) -Parse origin, type, position info, and event text -(Event handling requires binary parsing - see event-protocol.md) -``` - -## File Operations Reference - -For detailed information on each file's purpose, format, and operations, see **file-reference.md**. - -Key files: -- **ctl**: Send control commands, get window info -- **event**: Receive user interactions (clicks, typing, execution) -- **addr**: Set the current text address for data operations -- **body/tag**: Direct access to window content -- **data/xdata**: Read/write at current address +`0` `$` `0,$` `123` `123,456` `/regex/` `-/regex/` `.,+#10` `.+/regex/` ## Event Protocol -The event stream is the core of interactive acme tools. For complete event format details, parsing strategies, and handling patterns, see **event-protocol.md**. +Format: `origin type q0 q1 flag nr [text]\n` -Event format: `c1 c2 q0 q1 flag nr text` -- `c1`: Origin (E=keyboard, K=tag, M=mouse) -- `c2`: Type (x=execute, l=look, i=insert, d=delete, etc.) -- `q0, q1`: Text positions (byte offsets) -- `flag`: Additional state (chorded operations, etc.) -- `nr`: Number of runes in text -- `text`: The actual text involved +**Origin:** `E`=file write `F`=other file `K`=keyboard `M`=mouse -## Programming Language Considerations +**Type:** `D`/`d`=delete body/tag, `I`/`i`=insert body/tag, `L`/`l`=button3 body/tag, `R`/`r`=shift-button3 body/tag, `X`/`x`=button2 body/tag -**Language-agnostic**: The acme API only requires access to the 9P interface. Any language can interact with acme. +**flag (bitwise OR):** +- X/x: 1=builtin, 2=expansion follows, 8=chorded (2 msgs follow: arg, origin) +- L/l: 1=acme handles, 2=expansion follows, 4=file/window name -### plan9port Access Methods +**nr:** char count (0 if text >256, read from data) -1. **Shell scripts** (simplest): Use `9p read` and `9p write` commands -2. **Subprocess approach**: Call `9p` command from Python, Ruby, etc. -3. **9P library**: Use native 9P client library (Go, Python py9p, etc.) -4. **Direct namespace access**: On some systems, acme namespace is mounted as regular filesystem +**Acknowledge:** flag&1 events write back `origin type q0 q1\n` -Common approaches by language: -- **Shell**: `9p read acme/...`, `9p write acme/...` (recommended for scripts) -- **Python**: subprocess to call `9p`, or use `py9p` library -- **Go**: `9fans.net/go/plan9/client` library -- **C**: Call `9p` via `popen()`, or use `libixp`/`lib9p` -- **Any language**: Shell out to `9p` command via subprocess - -## Working with Supporting Files - -This skill includes detailed supporting documentation: - -- **file-reference.md**: Complete reference for all acme files -- **event-protocol.md**: Event format, parsing, and handling patterns -- **examples.md**: Code examples in multiple languages - -Read these files when you need detailed information about specific aspects of the API. - -## Common Patterns - -### Event Loop Template - -``` -1. Open $winid/event for reading -2. Loop: - a. Read one event (5×4 bytes + 1 byte + variable text) - b. Parse origin, type, positions, text - c. Handle event based on type - d. For certain events, write response to event file -3. On EOF or error, clean up and exit -``` - -### Text Manipulation Template - -``` -1. Write address to $winid/addr (e.g., "0,$" for entire body) -2. Read $winid/addr to get byte positions (q0, q1) -3. Read from or write to $winid/data -4. For multiple operations, use xdata to prevent address advancing -``` - -### Window Creation Template +## Patterns +**Create:** ```bash -# Create window and get ID (extract first field) -winid=$(9p read acme/new/ctl | awk '{print $1}') - -# Set window name -echo "name /path/to/file" | 9p write acme/$winid/ctl - -# Set up tag with commands -echo "/path/to/file Del Get Put" | 9p write acme/$winid/tag - -# Write initial content -echo "Initial text" | 9p write acme/$winid/body - -# Make visible -echo "show" | 9p write acme/$winid/ctl +id=$(9p read acme/new/ctl | awk '{print $1}') +echo "name /path" | 9p write acme/$id/ctl +echo "content" | 9p write acme/$id/body +echo "show" | 9p write acme/$id/ctl ``` -## Key Principles +**Event loop:** +``` +read acme/$id/event → parse → handle → ack if flag&1 → repeat (EOF=closed) +``` -1. **All positions are byte offsets**, not rune offsets (important for UTF-8) -2. **Events must be acknowledged**: Write the event back to prevent blocking -3. **Addresses are stateful**: The `addr` file maintains current position -4. **Clean/dirty state matters**: Mark windows clean/dirty to affect close behavior -5. **Tag is for commands**: Users expect standard acme commands in tag -6. **Body is for content**: Keep user text in body, tool output can go to either +**Text:** +```bash +echo '0,$' | 9p write acme/$id/addr +9p read acme/$id/data +echo "new" | 9p write acme/$id/data +``` -## Error Handling +## Key Points -- Failed operations on `ctl` return errors via read -- Invalid addresses on `addr` return errors -- Event stream EOF indicates window closed -- Check file operations for errors like any system I/O - -## Best Practices - -1. **Always handle events**: Unread events block acme -2. **Use addr for complex operations**: Don't manually calculate positions -3. **Preserve user intent**: Mark clean/dirty appropriately -4. **Follow acme conventions**: Put commands in tag, content in body -5. **Clean up on exit**: Close files, delete temporary windows -6. **Test with `window`**: Use `window` command to verify behavior - -## References - -- Plan 9 acme(4) man page -- Russ Cox's "Acme: A User Interface for Programmers" -- /sys/src/cmd/acme on Plan 9 source -- 9fans.net acme documentation - ---- - -When you need specific details about file operations or event handling, read the supporting files in this skill directory. +- addr: char offsets (not bytes) +- body/tag: write appends (offset ignored) +- data: uses addr, advances +- xdata: stops at end +- Events: ack flag&1, text >256 elided (nr=0) +- Unread events block acme diff --git a/skills/agent-kb/SKILL.md b/skills/agent-kb/SKILL.md index 394daa2..669cf0a 100644 --- a/skills/agent-kb/SKILL.md +++ b/skills/agent-kb/SKILL.md @@ -4,108 +4,67 @@ intent: knowledge, learning description: Query and maintain a local knowledge base of code insights and architecture notes. Use when encountering unfamiliar code, needing context beyond training, or when asked to save/update learned knowledge. --- -## Required Skills - -This skill requires the **denote** skill for file naming and frontmatter conventions. -Load and follow: `/home/lkn/.claude/skills/denote/SKILL.md` - # Agent Knowledge Base -## Purpose +**Location:** `~/doc/agent-kb/` -Leverage accumulated knowledge in `~/doc/agent-kb` to avoid redundant code research. Add new entries when discoveries warrant preservation. +**File format:** Follows **denote** skill conventions (load denote skill for naming/frontmatter rules). -## Answer Priority Hierarchy +## Usage -When answering user questions, follow this strict priority order: - -1. **KB First** - Search `~/doc/agent-kb/` for relevant entries -2. **Code Search** - If KB doesn't have the answer, search/inspect the codebase -3. **Web Search** - If code doesn't provide clarity, research online with proper citations -4. **Training Data** - Only as last resort to fill remaining gaps - -**Always cite your source** - Tell the user which level you're answering from. - -## When to Use - -- **When user asks any question** - Check KB first before answering -- Encountering unfamiliar code patterns, services, or architecture -- When user asks questions outside training data that would require code research -- Before extensive codebase research—check KB first -- When explicitly asked to save or update knowledge -- When a topic has been researched and should be preserved - -## Feeding Discoveries Back - -After significant code exploration, consider what was learned: - -1. **New knowledge**: Something not in the KB → offer to create entry -2. **Corrective knowledge**: Code contradicts KB → flag and offer to update -3. **Confirmatory knowledge**: Code confirms KB → no action needed (optionally note verification) - -**If KB contradicts code**: Stop and report the discrepancy. Ask: "KB says X, but code shows Y - should I update the KB?" Do not silently ignore KB errors. - -**End of exploration prompt**: "Did we discover anything worth preserving or correcting in the KB?" - -## KB Location - -``` -~/doc/agent-kb/ +**Search before answering:** +```bash +grep -il "keyword" ~/doc/agent-kb/*.md +ls -1 ~/doc/agent-kb/ ``` -## Querying the KB +**Read relevant entries before researching code.** -1. List available entries: - ```bash - ls -1 ~/doc/agent-kb/ - ``` +## Creating Entries -2. Search by tag or keyword: - ```bash - grep -l "pattern" ~/doc/agent-kb/*.md - ``` +1. Use denote naming: `date +%Y%m%dT%H%M%S` → `{timestamp}--{title}__{tags}.md` +2. Add frontmatter (see denote skill): `title`, `date`, `tags`, `identifier`, `verified`, `source` +3. One topic per file +4. Link to other entries: `denote:{identifier}` (e.g., `denote:20260130T171856`) +5. Don't auto-follow cross-references unless directly relevant -3. Search by content before answering questions: - ```bash - grep -il "keyword" ~/doc/agent-kb/*.md - ``` +## Updating Entries -4. Read relevant entries before researching code. +1. Read existing entry +2. Update content +3. Preserve identifier and filename +4. Update `verified` date in frontmatter +5. Add note on last line: `Updated YYYY-MM-DD: ` -## Creating KB Entries - -See the **denote** skill for file naming convention and frontmatter format. - -1. Generate timestamp: `date +%Y%m%dT%H%M%S` -2. Create file using Denote naming convention with `.md` extension -3. Add frontmatter (see denote skill for fields: `title`, `date`, `tags`, `identifier`, `verified`, `source`) -4. Keep entries focused—one topic per file. -5. **Link to other KB entries using `denote:{identifier}`** - e.g., "See denote:20260130T171856 for query details" -6. **Don't automatically follow cross-references** - Only load referenced documents if directly relevant to the current question. - -## Staleness Handling - -KB entries carry a `verified` date in frontmatter. Apply these thresholds when reading entries: +## Staleness | Age | Action | |-----|--------| -| Within 30 days | Trust entry, use directly | -| 31–90 days | Use with caution; flag as potentially stale | -| 90+ days | Verify against source code before acting; do not use blindly | +| ≤30 days | Trust, use directly | +| 31-90 days | Use with caution, flag as potentially stale | +| 90+ days | Verify against code before using | -**When you confirm an entry is still accurate**: update the `verified` date in frontmatter. +When confirmed accurate: update `verified` date. -**When you find an entry is wrong**: correct the content, update `verified`, and add a note on the last line: `Updated YYYY-MM-DD: `. +## What Belongs -## Updating KB Entries +**YES:** +- Code patterns, architecture, service behavior +- API contracts, data schemas, integration points +- Non-obvious implementation details +- Verified facts from code/docs -When knowledge becomes stale or incomplete: -1. Read the existing entry -2. Update content in place -3. Preserve the original identifier and filename -4. **Update `verified` date** in frontmatter if re-confirmed against code -5. **Add `verified` and `source` fields** to frontmatter if missing from older entries +**NO:** +- Speculation or design proposals +- "We could do X" alternatives +- Unverified assumptions +- Temporary workarounds -## What Belongs in the KB +## Feedback Loop -- **Only verifiable knowledge from authoritative sources** - code inspection, official documentation, or properly cited research. No speculation, design alternatives, or "we could do X" proposals. +After code exploration: +- New knowledge → offer to create entry +- KB contradicts code → stop, report discrepancy, ask to update +- KB confirmed → optionally note verification + +**If KB contradicts code:** Stop and report. Don't silently ignore KB errors. diff --git a/skills/beads/SKILL.md b/skills/beads/SKILL.md index 2b797c7..8fc4a65 100644 --- a/skills/beads/SKILL.md +++ b/skills/beads/SKILL.md @@ -6,530 +6,55 @@ description: Manage tasks using the beads 9P interface. Use when creating, updat # Beads Task System -## Purpose - -Beads is a hierarchical task tracking system accessed via 9P. Use it to track work items, their status, and dependencies. All operations persist immediately to a Dolt database, providing crash resilience and resumability. - -## When to Use - -- Creating or managing tasks -- Tracking work progress -- Setting up task hierarchies (parent/child) -- Managing blockers/dependencies -- Finding ready (unblocked) work - -## Atomic Operations - -Beads emphasizes atomic, single-purpose operations via the 9P control file: - -### Claiming Work -```bash -# Atomically sets assignee and status to in_progress -# MUST pass your agent ID (available as $AGENT_ID) -echo "claim bd-abc $AGENT_ID" | 9p write agent/beads/ctl -``` - -### Completing Work -```bash -# Atomically closes the bead -echo "complete bd-abc" | 9p write agent/beads/ctl -``` - -### Single-Purpose Commands -Each control command does exactly one thing: -- `new` - Create a bead -- `claim` - Claim a bead (sets assignee + status) -- `complete` - Complete a bead -- `fail` - Fail a bead with reason -- `update` - Update a single field -- `dep` - Add a dependency -- `undep` - Remove a dependency -- `delete` - Delete a bead -- `comment` - Add a comment -- `label` - Add a label -- `unlabel` - Remove a label - -### Immediate Feedback -After write operations, read back state to confirm: -```bash -echo "claim bd-abc" | 9p write agent/beads/ctl -9p read agent/beads/bd-abc/json | jq .status -# Output: "in_progress" -``` - -### No Batch Operations -Process beads one at a time in sequence: -```bash -# Correct: Sequential atomic operations -echo "claim bd-abc" | 9p write agent/beads/ctl -# ... do work ... -echo "complete bd-abc" | 9p write agent/beads/ctl - -# Incorrect: Don't try to batch multiple beads -``` - -## Dependency-Aware Workflow - -### Finding Ready Work -Use the `ready` endpoint to get beads with no blockers: -```bash -9p read agent/beads/ready | jq -# Returns JSON array of unblocked beads -``` - -### Creating Dependencies -Add a dependency so parent blocks child: -```bash -# Child bd-xyz is blocked by parent bd-abc -echo "dep bd-xyz bd-abc" | 9p write agent/beads/ctl -``` - -### Hierarchical Tasks -Create children with automatic hierarchical IDs: -```bash -# Create parent -echo "new 'Implement feature' 'Add new capability'" | 9p write agent/beads/ctl -# Get parent ID (e.g., bd-abc) - -# Create children - they get IDs bd-abc.1, bd-abc.2, etc. -echo "new 'Design API' 'Define interfaces' bd-abc" | 9p write agent/beads/ctl -echo "new 'Write tests' 'Add test coverage' bd-abc" | 9p write agent/beads/ctl -``` - -### Checking Blockers -Read the blockers field to see explicit dependencies blocking a bead: -```bash -9p read agent/beads/bd-xyz/json | jq .blockers -# Output: ["bd-abc"] - only shows explicit dependencies added via "dep" command -``` - -**Important**: The blockers field only contains beads added as explicit dependencies using `echo "dep " | 9p write agent/beads/ctl`. Child beads do NOT appear in the parent's blockers field. - -### Checking Outstanding Child Work -To determine if a parent bead has incomplete child tasks, query the children endpoint and filter by status: -```bash -# Get all non-closed children of bd-abc -9p read agent/beads/children/bd-abc | jq '[.[] | select(.status != "closed")]' - -# Count open children -9p read agent/beads/children/bd-abc | jq '[.[] | select(.status != "closed")] | length' - -# Check if any children remain open -9p read agent/beads/children/bd-abc | jq 'any(.status != "closed")' -``` - -### Recommended Workflow -1. Check ready work: `9p read agent/beads/ready` -2. Claim an unblocked bead: `echo "claim bd-xyz $AGENT_ID" | 9p write agent/beads/ctl` -3. Search KB for relevant context: `grep -ril "" ~/doc/agent-kb/` -4. Do the work (using KB-sourced file paths and patterns where available) -5. Before completing, check for child beads: `9p read agent/beads/children/bd-xyz | jq .` -6. If children exist: claim, work on, and complete each child before proceeding (see [Hierarchical Completion Protocol](#hierarchical-completion-protocol)) -7. Verify all children closed: `9p read agent/beads/children/bd-xyz | jq 'all(.status == "closed")'` -8. Only then complete the bead: `echo "complete bd-xyz" | 9p write agent/beads/ctl` -9. Completing a bead unblocks its dependents - -## Leaving Context for Future Agents - -Beads serve as dynamic/temporal memory for agent execution. Beyond status tracking, they capture decisions, dead ends, discoveries, and rationale — context that helps future agents working on related tasks avoid repeated mistakes and build on prior work. - -This is distinct from `agent-kb` (stable, reusable architectural knowledge). Beads hold *execution-time context*: what was tried, what failed, what was discovered, and why a particular approach was chosen. - -### When to Comment - -Comment on your bead as you work — not just at completion. Record: -- **Decisions**: "Chose approach Z because X failed due to Y." -- **Dead ends**: "Tried X, failed because Y. Avoided." -- **Discoveries**: "Found that endpoint /foo also rotates the refresh token." -- **Constraints**: "Avoided approach A because of constraint B (see bd-xyz)." - -Comments may come from agents or humans (e.g., a human reviewing work, recording a constraint, or explaining a decision). Treat both equally as authoritative context. - -```bash -echo "comment bd-abc \"Tried X first but hit rate limits. Switched to Y which batches requests.\"" | 9p write agent/beads/ctl -``` - -### When to Search Past Beads - -Before starting any non-trivial task, search completed beads for related terms to surface prior decisions and gotchas: - -```bash -9p read agent/beads/search/authentication | jq '.[].title' -9p read agent/beads/search/refresh-token | jq '.[].description' -``` - -When a bead looks relevant, read its full event history to see comments — this is where the most valuable context lives, including human-authored notes: - -```bash -9p read agent/beads/bd-abc/events | jq '.[] | select(.type == "comment") | .body' -``` - -### What NOT to Do - -- ❌ **NEVER create "knowledge beads"** solely to record information — this pollutes the task system with non-task entries -- ❌ Don't leave your bead with only status updates — rationale and discoveries are more valuable to future agents than "completed X" - -Context belongs *in your task bead*, recorded as comments during execution. - -## Description Quality and File Addressing - -### What Makes a Good Description - -Every bead description must enable a bot to complete the task cold — no codebase exploration, no guessing. The beads server enforces this with lint warnings emitted to stderr on `new`. A high-quality description: - -- Starts with an **imperative verb**: Fix, Add, Update, Refactor, Implement, ... -- Names at least one **file path** with a recognized extension (.go, .py, .ts, .js, .rs) or path component (/internal/, /cmd/, /src/, /pkg/) -- Identifies a **precise location**: function name in backticks, or an Acme file address (see below) -- Wraps all identifiers in **backticks**: `` `lintDescription()` ``, `` `--no-lint` ``, `` `TypeName` `` -- Includes a **"how" signal**: "following the pattern in X", "same as Y", "mirrors Z" -- States an **observable acceptance criterion**: "must return ...", "should emit ...", "returns ..." -- Avoids **vague language**: somehow, maybe, etc., stuff, try to, a bit -- Avoids **first-person voice**: I need, we want, I'll -- For descriptions > 150 chars, includes a **cross-reference**: `bd-XXX` or a URL - -### File Addressing - -When referencing source locations, use **Acme/sam address syntax** — not the common but incorrect hyphen form. - -**Correct forms (from `/home/lkn/plan9/plumb/fileaddr`):** - -``` -beads.go:123 line 123 -beads.go:123,125 lines 123 to 125 (comma range) -beads.go:/funcName/ regex search (pattern ≥ 4 chars) -beads.go:#4096 character offset 4096 -``` - -**Never use:** - -``` -beads.go:123-125 ✗ hyphen range is invalid in Acme — use comma -``` - -The linter warns when it detects the hyphen form. The Conductor cold-completion gate also checks for correct Acme syntax before assigning P1/P2 beads. - -### Lint Rules Summary - -The server checks descriptions against these rules (warnings go to stderr; bypass with `--no-lint`): - -| Rule | Signal checked | -|------|---------------| -| File path | `.go`/`.py`/etc. or `/internal/`/`/cmd/`/... | -| Location | `func()`, Acme address, `L123`, `:123`, `#123` | -| Minimum length | ≥ 80 characters | -| Acceptance criterion | should / must / returns / displays / assert / verify / accept / expect | -| Acme address format | No `file:N-N` hyphen ranges | -| Imperative start | Not "Need to" / "Should" / "We need" / "The X" | -| Vague language | No somehow / maybe / etc. / stuff / try to | -| How signal | following / same as / pattern from / similar to / mirrors | -| First-person | No I need / I want / we should / we'll | -| Forbidden phrases | No "fix this" / "update this" / "make it work" | -| Inline code | Backtick identifier required when file path present | -| Cross-reference | `bd-XXX` or URL required for descriptions > 150 chars | - -## JSON Output for Programmatic Use - -All read endpoints return JSON for easy parsing. - -### Available Endpoints - -**List Operations:** -- `agent/beads/list` - All beads -- `agent/beads/ready` - Beads with no blockers -- `agent/beads/blocked` - Beads that have blockers -- `agent/beads/stale` - Beads 30+ days old -- `agent/beads/stats` - Statistics (counts by status) - -**Query Operations:** -- `agent/beads/query` - Query beads (write JSON filter, then read results) -- `agent/beads/search/` - Search beads by term -- `agent/beads/by-ref/` - Find bead by external reference -- `agent/beads/label/