Move mcptools to anvillm-mcp

This commit is contained in:
Levi Neely 2026-03-20 15:20:14 +01:00
parent 29fe71d24d
commit 170d3ca3df
52 changed files with 0 additions and 1849 deletions

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Add a dependency (child depends on parent)
# Usage: add_dependency.sh --mount <mount> --child <child-id> --parent <parent-id>
set -euo pipefail
MOUNT=""
CHILD=""
PARENT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--child) CHILD="$2"; shift 2 ;;
--parent) PARENT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$CHILD" ] || [ -z "$PARENT" ]; then
echo "usage: add_dependency.sh --mount <mount> --child <child-id> --parent <parent-id>" >&2
exit 1
fi
echo "dep $CHILD $PARENT" | 9p write beads/$MOUNT/ctl
echo "$CHILD depends on $PARENT"

View File

@ -1,39 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Batch create beads from JSON array. Scope is auto-derived from cwd.
# Usage: batch_create_beads.sh --mount <mount> --json <json-array>
set -euo pipefail
MOUNT=""
JSON=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--json) JSON="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$JSON" ]; then
echo "usage: batch_create_beads.sh --mount <mount> --json <json-array>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
SCOPE="${REL_PATH%%/*}"
fi
# Inject scope into each bead in the JSON array
if [ -n "$SCOPE" ]; then
JSON=$(echo "$JSON" | jq --arg scope "$SCOPE" '[.[] | . + {scope: $scope}]')
fi
echo "batch-create $JSON" | 9p write "beads/$MOUNT/ctl"
echo "batch created beads"

View File

@ -1,63 +0,0 @@
#!/bin/bash
# capabilities: estimation
# description: Calibrate time estimation model from completion data; auto-updates taxonomy when 'other' accumulates
# Usage: calibrate_time_estimate.sh
set -euo pipefail
TAXONOMY_FILE="$HOME/.config/anvillm/estimation/taxonomy.json"
MODEL_FILE="$HOME/.local/share/anvillm/estimation/model.json"
LOG_FILE="$HOME/.local/share/anvillm/estimation/completions.jsonl"
MIN_SAMPLES=3
if [ ! -f "$LOG_FILE" ]; then
echo "No completion data at $LOG_FILE — nothing to calibrate."
exit 0
fi
TOTAL=$(wc -l < "$LOG_FILE")
echo "Processing $TOTAL completion records..."
OTHER_THRESHOLD=$(jq -r '.other_threshold // 5' "$TAXONOMY_FILE")
# Compute per-domain median actual_seconds (only for domains with >= MIN_SAMPLES records)
NEW_BASE=$(jq -rs --argjson min "$MIN_SAMPLES" '
[ .[] | select(.actual_seconds != null) ] |
group_by(.domain) |
map(select(length >= $min) | {
key: .[0].domain,
value: ( map(.actual_seconds) | sort | .[(length / 2 | floor)] )
}) |
from_entries
' "$LOG_FILE")
# Load or initialize model
if [ -f "$MODEL_FILE" ]; then
CURRENT_MODEL=$(cat "$MODEL_FILE")
else
CURRENT_MODEL='{"base_seconds": {}, "child_multiplier": 300, "desc_multiplier": 0.5}'
fi
# Merge updated base_seconds into model
echo "$CURRENT_MODEL" | jq --argjson new "$NEW_BASE" '.base_seconds += $new' > "$MODEL_FILE"
echo "Model updated: $MODEL_FILE"
# Check 'other' accumulation for taxonomy auto-update
if jq -e 'select(.domain == "other")' "$LOG_FILE" >/dev/null 2>&1; then
# Count inferred_labels within 'other' records
while IFS=$'\t' read -r COUNT LABEL; do
[ -z "$LABEL" ] || [ "$LABEL" = "null" ] || [ "$LABEL" = "other" ] && continue
if [ "$COUNT" -ge "$OTHER_THRESHOLD" ]; then
EXISTS=$(jq -r --arg l "$LABEL" '.categories[] | select(. == $l)' "$TAXONOMY_FILE" 2>/dev/null || true)
if [ -z "$EXISTS" ]; then
echo "Auto-adding taxonomy category: $LABEL (${COUNT} samples)"
jq --arg c "$LABEL" '.categories += [$c]' "$TAXONOMY_FILE" > "${TAXONOMY_FILE}.tmp"
mv "${TAXONOMY_FILE}.tmp" "$TAXONOMY_FILE"
fi
fi
done < <(jq -r 'select(.domain == "other") | .inferred_label // "null"' "$LOG_FILE" \
| sort | uniq -c | sort -rn \
| awk '{print $1"\t"$2}')
fi
echo "Calibration complete."

View File

@ -1,66 +0,0 @@
#!/usr/bin/env bash
# capabilities: web
# description: Capture browser window showing a specific URL: capture_browser.sh [output_path] [url_pattern]
set -e
# Verify running under landrun (test filesystem restriction)
OUTPUT="${1:-${TMPDIR:-/tmp}/browser_capture.png}"
URL_PATTERN="${2:-localhost}"
case "$(uname -s)" in
Darwin)
# macOS: use osascript + screencapture
osascript -e 'tell application "Google Chrome" to activate' 2>/dev/null
sleep 0.3
osascript -e "tell application \"Google Chrome\" to set index of (first window whose name contains \"$URL_PATTERN\") to 1" 2>/dev/null
sleep 0.3
screencapture -x "$OUTPUT"
;;
Linux)
if [ -z "$DISPLAY" ]; then
echo "ERROR: DISPLAY not set" >&2
exit 1
fi
# Linux: use brotab + wmctrl + import
TAB_INFO=$(brotab list | grep -i "$URL_PATTERN" | head -1)
if [ -z "$TAB_INFO" ]; then
echo "ERROR: No tab matching '$URL_PATTERN'" >&2
exit 1
fi
TAB_ID=$(echo "$TAB_INFO" | cut -f1)
TAB_TITLE=$(echo "$TAB_INFO" | cut -f2)
echo "Found tab: $TAB_ID ($TAB_TITLE)" >&2
brotab activate "$TAB_ID"
sleep 0.5
WIN_ID=$(wmctrl -l | grep -i "$TAB_TITLE" | head -1 | awk '{print $1}')
if [ -z "$WIN_ID" ]; then
WIN_ID=$(wmctrl -l | grep -iE "firefox|chrome|chromium" | head -1 | awk '{print $1}')
fi
if [ -z "$WIN_ID" ]; then
echo "ERROR: Could not find browser window" >&2
exit 1
fi
echo "Capturing window: $WIN_ID" >&2
wmctrl -i -a "$WIN_ID"
sleep 0.3
import -window "$WIN_ID" "$OUTPUT"
;;
*)
echo "ERROR: Unsupported OS: $(uname -s)" >&2
exit 1
;;
esac
if [ -f "$OUTPUT" ]; then
echo "$OUTPUT"
else
echo "ERROR: Failed to capture" >&2
exit 1
fi

View File

@ -1,37 +0,0 @@
#!/bin/bash
# capabilities: messaging
# description: Read messages from agent inbox (uses $AGENT_ID env var)
set -euo pipefail
# Verify running under landrun (test filesystem restriction)
if [ -z "${AGENT_ID:-}" ]; then
echo "Error: \$AGENT_ID is not set. Stop work and inform the user that \$AGENT_ID is not set." >&2
exit 1
fi
agent_id="$AGENT_ID"
inbox_path="anvillm/${agent_id}/inbox"
files=$(9p ls "$inbox_path" 2>/dev/null | grep '\.json$' || true)
if [ -z "$files" ]; then
echo "No messages"
exit 0
fi
msg_file=$(echo "$files" | head -1)
msg_path="${inbox_path}/${msg_file}"
msg_id="${msg_file%.json}"
data=$(9p read "$msg_path" 2>/dev/null || echo '{}')
from=$(echo "$data" | jq -r '.from // "unknown"')
type=$(echo "$data" | jq -r '.type // "unknown"')
subject=$(echo "$data" | jq -r '.subject // ""')
body=$(echo "$data" | jq -r '.body // ""')
echo "complete ${msg_id}" | 9p write "anvillm/${agent_id}/ctl" 2>/dev/null || true
echo "From: ${from}"
echo "Type: ${type}"
echo "Subject: ${subject}"
echo ""
echo "${body}"

View File

@ -1,36 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Claim a bead for work. Assignee is taken from $AGENT_ID.
# Usage: claim_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: claim_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
if [ -z "${AGENT_ID:-}" ]; then
echo "error: AGENT_ID is not set" >&2
exit 1
fi
echo "claim $BEAD_ID $AGENT_ID" | 9p write beads/$MOUNT/ctl
assignee=$(9p read beads/$MOUNT/$BEAD_ID/json 2>/dev/null | jq -r '.assignee // empty')
if [ "$assignee" != "$AGENT_ID" ]; then
echo "error: claim failed (bead is assigned to '$assignee')" >&2
exit 1
fi
echo "claimed $BEAD_ID → $AGENT_ID"

View File

@ -1,117 +0,0 @@
#!/bin/bash
# capabilities: code-exploration
# description: Token-efficient code exploration with preview/fetch phases
set -euo pipefail
CACHE_BASE="${XDG_CACHE_HOME:-$HOME/.cache}/anvillm/code-explorer"
slugify() {
echo "$1" | sed 's/-/--/g; s|/|-|g'
}
get_cache_dir() {
local dir="${1:-$PWD}"
local slug=$(slugify "$dir")
echo "$CACHE_BASE/$slug"
}
cmd_init() {
local dir="${1:-$PWD}"
local cache=$(get_cache_dir "$dir")
mkdir -p "$cache"
# Build file index
find "$dir" -type f \
! -path '*/.git/*' \
! -path '*/node_modules/*' \
! -path '*/vendor/*' \
! -path '*/__pycache__/*' \
! -path '*/target/*' \
! -path '*/dist/*' \
! -path '*/build/*' \
-printf '%P\t%s\t%T@\n' 2>/dev/null > "$cache/index.tsv"
# Build symbol index if ctags available
if command -v ctags &>/dev/null; then
ctags -R --fields=+n -f "$cache/tags" "$dir" 2>/dev/null || true
fi
echo "Indexed $(wc -l < "$cache/index.tsv") files in $cache"
}
cmd_preview() {
local pattern="$1"
local dir="${2:-$PWD}"
local lang="${3:-}"
local include=""
[ -n "$lang" ] && include="--include=*.$lang"
rg -c $include \
--glob '!.git' \
--glob '!node_modules' \
--glob '!vendor' \
--glob '!__pycache__' \
--glob '!target' \
--glob '!dist' \
--glob '!build' \
"$pattern" "$dir" 2>/dev/null | head -50
}
cmd_fetch() {
local pattern="$1"
local file="$2"
local context="${3:-2}"
rg -n -C "$context" "$pattern" "$file" 2>/dev/null | head -100
}
cmd_symbols() {
local pattern="$1"
local dir="${2:-$PWD}"
local cache=$(get_cache_dir "$dir")
if [ -f "$cache/tags" ]; then
grep -i "$pattern" "$cache/tags" | head -30
else
echo "No symbol index. Run: code_explorer init" >&2
exit 1
fi
}
cmd_tree() {
local dir="${1:-$PWD}"
local depth="${2:-2}"
local lang="${3:-}"
local name_filter=""
[ -n "$lang" ] && name_filter="-name '*.$lang'"
find "$dir" -maxdepth "$depth" -type f \
! -path '*/.git/*' \
! -path '*/node_modules/*' \
$name_filter \
2>/dev/null | head -100
}
case "${1:-help}" in
init) cmd_init "${2:-}" ;;
preview) cmd_preview "$2" "${3:-}" "${4:-}" ;;
fetch) cmd_fetch "$2" "$3" "${4:-2}" ;;
symbols) cmd_symbols "$2" "${3:-}" ;;
tree) cmd_tree "${2:-}" "${3:-2}" "${4:-}" ;;
cache-dir) get_cache_dir "${2:-$PWD}" ;;
*)
cat <<EOF
Usage: code_explorer <command> [args]
Commands:
init [dir] Build index for directory (default: \$PWD)
preview <pattern> [dir] [ext] Count matches per file (cheap)
fetch <pattern> <file> [ctx] Get matches with context (default: 2 lines)
symbols <pattern> [dir] Search symbol index
tree [dir] [depth] [ext] List files (default depth: 2)
cache-dir [dir] Show cache location
EOF
;;
esac

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Add a comment to a bead
# Usage: comment_bead.sh --mount <mount> --id <bead-id> --text <text>
set -euo pipefail
MOUNT=""
BEAD_ID=""
TEXT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--text) TEXT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$TEXT" ]; then
echo "usage: comment_bead.sh --mount <mount> --id <bead-id> --text <text>" >&2
exit 1
fi
printf "comment %s '%s'\n" "$BEAD_ID" "$TEXT" | 9p write beads/$MOUNT/ctl
echo "commented on $BEAD_ID"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Complete a bead
# Usage: complete_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: complete_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
echo "complete $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "completed $BEAD_ID"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Set a beads database configuration key
# Usage: config_beads.sh --mount <mount> --key <key> --value <value>
set -euo pipefail
MOUNT=""
KEY=""
VALUE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--key) KEY="$2"; shift 2 ;;
--value) VALUE="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$KEY" ]; then
echo "usage: config_beads.sh --mount <mount> --key <key> --value <value>" >&2
exit 1
fi
echo "config $KEY $VALUE" | 9p write beads/$MOUNT/ctl
echo "config $KEY = $VALUE"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: agents
# description: Control a session (stop|restart|kill|refresh)
# Usage: control_session.sh --session-id <session-id> --command <stop|restart|kill|refresh>
set -euo pipefail
SESSION_ID=""
COMMAND=""
while [[ $# -gt 0 ]]; do
case "$1" in
--session-id) SESSION_ID="$2"; shift 2 ;;
--command) COMMAND="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$SESSION_ID" ] || [ -z "$COMMAND" ]; then
echo "usage: control_session.sh --session-id <session-id> --command <stop|restart|kill|refresh>" >&2
exit 1
fi
echo "$COMMAND" | 9p write "anvillm/$SESSION_ID/ctl"
echo "$COMMAND: $SESSION_ID"

View File

@ -1,48 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Create a new bead. Scope is auto-derived from cwd relative to mount.
# Usage: create_bead.sh --mount <mount> --title <title> [--desc <desc>] [--parent <id>] [--no-lint] [--capability low|standard|high]
set -euo pipefail
MOUNT=""
TITLE=""
DESC=""
PARENT=""
NOLINT=""
CAP=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--title) TITLE="$2"; shift 2 ;;
--desc) DESC="$2"; shift 2 ;;
--parent) PARENT="$2"; shift 2 ;;
--no-lint) NOLINT="--no-lint"; shift ;;
--capability) CAP="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$TITLE" ]; then
echo "usage: create_bead.sh --mount <mount> --title <title> [--desc <desc>] [--parent <id>] [--no-lint] [--capability low|standard|high]" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
SCOPE="${REL_PATH%%/*}"
fi
CMD="new '$TITLE' '$DESC'"
[ -n "$PARENT" ] && CMD="$CMD $PARENT"
[ -n "$NOLINT" ] && CMD="$CMD $NOLINT"
[ -n "$CAP" ] && CMD="$CMD capability=$CAP"
[ -n "$SCOPE" ] && CMD="$CMD scope=$SCOPE"
echo "$CMD" | 9p write beads/$MOUNT/ctl
echo "created (deferred): $TITLE"

View File

@ -1,33 +0,0 @@
#!/bin/bash
# capabilities: agents
# description: Create a new agent session
# Usage: create_session.sh --backend <backend> --cwd <cwd> [--sandbox <sandbox>] [--model <model>]
set -euo pipefail
BACKEND=""
CWD=""
SANDBOX=""
MODEL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--backend) BACKEND="$2"; shift 2 ;;
--cwd) CWD="$2"; shift 2 ;;
--sandbox) SANDBOX="$2"; shift 2 ;;
--model) MODEL="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$BACKEND" ] || [ -z "$CWD" ]; then
echo "usage: create_session.sh --backend <backend> --cwd <cwd> [--sandbox <sandbox>] [--model <model>]" >&2
exit 1
fi
CMD="new $BACKEND $CWD"
[ -n "$SANDBOX" ] && CMD="$CMD sandbox=$SANDBOX"
[ -n "$MODEL" ] && CMD="$CMD model=$MODEL"
echo "$CMD" | 9p write anvillm/ctl
echo "created session: $BACKEND $CWD"

View File

@ -1,32 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Defer a bead, optionally until a specific time
# Usage: defer_bead.sh --mount <mount> --id <bead-id> [--until <RFC3339-time>]
set -euo pipefail
MOUNT=""
BEAD_ID=""
UNTIL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--until) UNTIL="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: defer_bead.sh --mount <mount> --id <bead-id> [--until <RFC3339-time>]" >&2
exit 1
fi
if [ -n "$UNTIL" ]; then
echo "defer $BEAD_ID until $UNTIL" | 9p write beads/$MOUNT/ctl
echo "deferred $BEAD_ID until $UNTIL"
else
echo "defer $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "deferred $BEAD_ID"
fi

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Delete a bead
# Usage: delete_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: delete_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
echo "delete $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "deleted $BEAD_ID"

View File

@ -1,30 +0,0 @@
#!/bin/bash
# capabilities: discovery
# description: Discover available skills by keyword
set -euo pipefail
if [ $# -ne 1 ]; then
echo "Usage: discover_skill <keyword>" >&2
exit 1
fi
keyword="$1"
results=""
# Search each skill file for the keyword
while IFS= read -r file; do
[ "${file%.md}" = "$file" ] && continue # skip non-.md entries
name="${file%.md}"
content=$(9p read "anvillm/skills/$file")
if echo "$content" | grep -qi "$keyword"; then
desc=$(echo "$content" | grep -m1 '^description:' | sed 's/^description: *//')
results="${results:+$results
}$name $desc"
fi
done < <(9p ls anvillm/skills)
if [ -n "$results" ]; then
echo "$results" | sort -u
else
echo "No skills found matching: $keyword"
fi

View File

@ -1,72 +0,0 @@
#!/bin/bash
# capabilities: estimation
# description: Estimate LLM task completion time from bead signals
# Usage: estimate_time.sh '<json>'
# Input JSON: {"domain": "api", "child_bead_count": 3, "description_length": 450, "inferred_label": "api"}
# Output JSON: {"estimate_seconds": 1800, "tier": "moderate", "deadline_seconds": 3600}
set -euo pipefail
if [ $# -lt 1 ]; then
echo "usage: estimate_time.sh '<json-signals>'" >&2
exit 1
fi
TAXONOMY_FILE="$HOME/.config/anvillm/estimation/taxonomy.json"
MODEL_FILE="$HOME/.local/share/anvillm/estimation/model.json"
INPUT="$1"
# Extract signals
DOMAIN=$(echo "$INPUT" | jq -r '.domain // "other"')
CHILD_COUNT=$(echo "$INPUT" | jq -r '.child_bead_count // 0')
DESC_LEN=$(echo "$INPUT" | jq -r '.description_length // 0')
# Validate domain against taxonomy; fall back to "other" if unrecognized
if [ -f "$TAXONOMY_FILE" ]; then
VALID=$(jq -r --arg d "$DOMAIN" '.categories[] | select(. == $d)' "$TAXONOMY_FILE" 2>/dev/null || true)
if [ -z "$VALID" ]; then
DOMAIN="other"
fi
fi
# Load fitted constants from model.json, or use cold-start defaults
if [ -f "$MODEL_FILE" ]; then
BASE=$(jq -r --arg d "$DOMAIN" '.base_seconds[$d] // 1200' "$MODEL_FILE")
CHILD_MULT=$(jq -r '.child_multiplier // 300' "$MODEL_FILE")
DESC_MULT=$(jq -r '.desc_multiplier // 0.5' "$MODEL_FILE")
else
case "$DOMAIN" in
ui) BASE=600 ;;
api) BASE=900 ;;
data-model) BASE=1200 ;;
infra) BASE=1500 ;;
testing) BASE=600 ;;
refactor) BASE=1800 ;;
docs) BASE=300 ;;
security) BASE=1800 ;;
performance) BASE=1500 ;;
research) BASE=1200 ;;
*) BASE=1200 ;;
esac
CHILD_MULT=300
DESC_MULT=0.5
fi
# Compute estimate and deadline (2x estimate)
ESTIMATE=$(awk -v base="$BASE" -v cc="$CHILD_COUNT" -v cm="$CHILD_MULT" -v dl="$DESC_LEN" -v dm="$DESC_MULT" \
'BEGIN { printf "%d", base + (cc * cm) + (dl * dm) }')
DEADLINE=$(awk -v e="$ESTIMATE" 'BEGIN { printf "%d", e * 2 }')
# Classify tier
if [ "$ESTIMATE" -lt 300 ]; then TIER="trivial"
elif [ "$ESTIMATE" -lt 1800 ]; then TIER="moderate"
elif [ "$ESTIMATE" -lt 7200 ]; then TIER="large"
else TIER="very_large"
fi
jq -n \
--argjson est "$ESTIMATE" \
--arg tier "$TIER" \
--argjson dl "$DEADLINE" \
'{"estimate_seconds": $est, "tier": $tier, "deadline_seconds": $dl}'

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Fail a bead with reason
# Usage: fail_bead.sh --mount <mount> --id <bead-id> --reason <reason>
set -euo pipefail
MOUNT=""
BEAD_ID=""
REASON=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--reason) REASON="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$REASON" ]; then
echo "usage: fail_bead.sh --mount <mount> --id <bead-id> --reason <reason>" >&2
exit 1
fi
printf "fail %s '%s'\n" "$BEAD_ID" "$REASON" | 9p write beads/$MOUNT/ctl
echo "failed $BEAD_ID: $REASON"

View File

@ -1,92 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Import GitHub issue into beads. Scope is auto-derived from cwd.
# Usage: github_to_beads.sh --mount <mount> --repo <owner/repo> --issue <issue-number>
set -euo pipefail
MOUNT=""
REPO=""
ISSUE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--repo) REPO="$2"; shift 2 ;;
--issue) ISSUE="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$REPO" ] || [ -z "$ISSUE" ]; then
echo "usage: github_to_beads.sh --mount <mount> --repo <owner/repo> --issue <issue-number>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
SCOPE="${REL_PATH%%/*}"
fi
SCOPE_ARG=""
[ -n "$SCOPE" ] && SCOPE_ARG="scope=$SCOPE"
# Check if already imported
if 9p read "beads/$MOUNT/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\" '' $SCOPE_ARG" | 9p write "beads/$MOUNT/ctl"
# Get created bead ID
bead_id=$(9p read "beads/$MOUNT/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 "beads/$MOUNT/ctl"
fi
# Update status if closed
if [[ "$status" == "closed" ]]; then
echo "update $bead_id status closed" | 9p write "beads/$MOUNT/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 $SCOPE_ARG" | 9p write "beads/$MOUNT/ctl"
fi
done
fi
echo "$bead_id"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Initialize beads project with issue prefix
# Usage: init_beads.sh --mount <mount> [--prefix <prefix>]
set -euo pipefail
MOUNT=""
PREFIX="bd"
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--prefix) PREFIX="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: init_beads.sh --mount <mount> [--prefix <prefix>]" >&2
exit 1
fi
echo "init $PREFIX" | 9p write "beads/$MOUNT/ctl"
echo "initialized $MOUNT (prefix: $PREFIX)"

View File

@ -1,97 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Import Jira ticket hierarchy into beads. Scope is auto-derived from cwd.
# Usage: jira_to_beads.sh --mount <mount> --ticket <ticket-key>
set -euo pipefail
MOUNT=""
TICKET=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--ticket) TICKET="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$TICKET" ]; then
echo "usage: jira_to_beads.sh --mount <mount> --ticket <ticket-key>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
SCOPE="${REL_PATH%%/*}"
fi
SCOPE_ARG=""
[ -n "$SCOPE" ] && SCOPE_ARG="scope=$SCOPE"
# Check if already imported
if 9p read "beads/$MOUNT/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 $SCOPE_ARG" | 9p write "beads/$MOUNT/ctl"
else
echo "new \"$title\" \"$description\" '' $SCOPE_ARG" | 9p write "beads/$MOUNT/ctl"
fi
# Get created bead ID
local bead_id
bead_id=$(9p read "beads/$MOUNT/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"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: agents
# description: Kill agent session(s) running in the given directory
# Usage: kill_agent.sh --agent-id <agent-id>
set -euo pipefail
AGENT_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--agent-id) AGENT_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$AGENT_ID" ]; then
echo "usage: kill_agent.sh --agent-id <agent-id>" >&2
exit 1
fi
if echo "kill" | 9p write "anvillm/$AGENT_ID/ctl" 2>/dev/null; then
echo "Killed $AGENT_ID"
else
echo "No session found with id $AGENT_ID" >&2
exit 1
fi

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Add a label to a bead
# Usage: label_bead.sh --mount <mount> --id <bead-id> --label <label>
set -euo pipefail
MOUNT=""
BEAD_ID=""
LABEL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--label) LABEL="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$LABEL" ]; then
echo "usage: label_bead.sh --mount <mount> --id <bead-id> --label <label>" >&2
exit 1
fi
echo "label $BEAD_ID $LABEL" | 9p write beads/$MOUNT/ctl
echo "labeled $BEAD_ID: $LABEL"

View File

@ -1,32 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: List all open beads (JSON array). Filters by scope derived from cwd (strict match).
# Usage: list_beads.sh --mount <mount>
set -euo pipefail
MOUNT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: list_beads.sh --mount <mount>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
MY_SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
MY_SCOPE="${REL_PATH%%/*}"
fi
# Strict match: scope must equal (both empty or both same value)
9p read "beads/$MOUNT/list" 2>/dev/null | jq --arg scope "$MY_SCOPE" '[.[] | select((.scope // "") == $scope) | {id, priority, title, status, scope}]' || echo "[]"

View File

@ -1,7 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: List mounted beads projects
set -euo pipefail
9p read beads/mtab 2>/dev/null || echo "No mounted projects"

View File

@ -1,32 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: List ready/claimable beads (JSON array). Filters by scope derived from cwd (strict match).
# Usage: list_ready_beads.sh --mount <mount>
set -euo pipefail
MOUNT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: list_ready_beads.sh --mount <mount>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
MY_SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
MY_SCOPE="${REL_PATH%%/*}"
fi
# Strict match: scope must equal (both empty or both same value)
9p read "beads/$MOUNT/ready" 2>/dev/null | jq --arg scope "$MY_SCOPE" '[.[] | select((.scope // "") == $scope) | {id, priority, title, status, scope}]' || echo "[]"

View File

@ -1,18 +0,0 @@
#!/bin/bash
# capabilities: discovery
# description: List all available roles (JSON array)
set -euo pipefail
# Verify running under landrun (test filesystem restriction)
9p ls anvillm/roles 2>/dev/null | grep -v '^help$' | while read focus_area; do
9p ls "anvillm/roles/$focus_area" 2>/dev/null | while read role_file; do
role_name="${role_file%.md}"
desc=$(9p read "anvillm/roles/$focus_area/$role_file" 2>/dev/null | awk '/^---$/,/^---$/ {if (/^description:/) {sub(/^description: */, ""); print; exit}}')
printf '%s\t%s\t%s\n' "$focus_area" "$role_name" "$desc"
done
done | jq -Rs '
split("\n") | map(select(length > 0)) | map(
split("\t") | {focus_area: .[0], name: .[1], description: .[2]}
)
'

View File

@ -1,8 +0,0 @@
#!/bin/bash
# capabilities: agents
# description: List all active agent sessions (tab-separated: id, backend, state, alias, role, cwd)
set -euo pipefail
# Verify running under landrun (test filesystem restriction)
9p read anvillm/list 2>/dev/null || true

View File

@ -1,23 +0,0 @@
#!/bin/bash
# capabilities: discovery
# description: List all available skills (JSON array)
set -euo pipefail
# Verify running under landrun (test filesystem restriction)
if [ -z "${ANVILLM_SKILLS_PATH:-}" ]; then
echo "[]"
exit 0
fi
for dir in "$ANVILLM_SKILLS_PATH"/*; do
if [ -d "$dir" ] && [ -f "$dir/SKILL.md" ]; then
name=$(basename "$dir")
desc=$(grep -m1 '^description:' "$dir/SKILL.md" | sed 's/^description: *//' || true)
printf '%s\t%s\n' "$name" "$desc"
fi
done | jq -Rs '
split("\n") | map(select(length > 0)) | map(
split("\t") | {name: .[0], description: .[1]}
)
'

View File

@ -1,20 +0,0 @@
#!/bin/bash
# capabilities: discovery
# description: Load a skill's SKILL.md by name
set -euo pipefail
# Usage: load_skill <skill-name> [skill-name...]
#
# Accepts either bare names or paths (the last component is used):
# anvillm-sessions
# skills/agents/anvillm-sessions (legacy path format; last component is used)
if [ $# -lt 1 ]; then
echo "Usage: load_skill <skill-name> [skill-name...]" >&2
exit 1
fi
for arg in "$@"; do
name="${arg##*/}"
9p read "anvillm/skills/${name}.md"
done

View File

@ -1,41 +0,0 @@
#!/bin/bash
# Display message history for an agent or user.
# Usage: mail_history.sh --agent-id <agent-id|user> [--date YYYYMMdd]
set -euo pipefail
AGENT_ID=""
DATE_FILTER=""
while [[ $# -gt 0 ]]; do
case "$1" in
--agent-id) AGENT_ID="$2"; shift 2 ;;
--date) DATE_FILTER="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [[ -z "$AGENT_ID" ]]; then
echo "usage: mail_history.sh --agent-id <agent-id|user> [--date YYYYMMdd]" >&2
exit 1
fi
MAIL_DIR="$HOME/.local/share/anvillm/mail/$AGENT_ID"
shopt -s nullglob
if [[ -n "$DATE_FILTER" ]]; then
SENT="$MAIL_DIR/${DATE_FILTER}-sent.jsonl"
RECV="$MAIL_DIR/${DATE_FILTER}-recv.jsonl"
FILES=()
[[ -f "$SENT" ]] && FILES+=("$SENT") || echo "Could not get sent messages for $DATE_FILTER" >&2
[[ -f "$RECV" ]] && FILES+=("$RECV") || echo "Could not get received messages for $DATE_FILTER" >&2
else
FILES=("$MAIL_DIR"/*-sent.jsonl "$MAIL_DIR"/*-recv.jsonl)
fi
shopt -u nullglob
if [[ ${#FILES[@]} -eq 0 ]]; then
echo "No messages for $AGENT_ID"
exit 0
fi
cat "${FILES[@]}" | jq -cs 'sort_by(.ts) | .[]'

View File

@ -1,42 +0,0 @@
#!/bin/bash
# Search message history for an agent or user by regex pattern.
# Usage: mail_search.sh --agent-id <agent-id|user> --pattern <regex> [--date YYYYMMdd]
set -euo pipefail
AGENT_ID=""
PATTERN=""
DATE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--agent-id) AGENT_ID="$2"; shift 2 ;;
--pattern) PATTERN="$2"; shift 2 ;;
--date) DATE="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [[ -z "$AGENT_ID" ]] || [[ -z "$PATTERN" ]]; then
echo "usage: mail_search.sh --agent-id <agent-id|user> --pattern <regex> [--date YYYYMMdd]" >&2
exit 1
fi
MAIL_DIR="$HOME/.local/share/anvillm/mail/$AGENT_ID"
shopt -s nullglob
if [[ -n "$DATE" ]]; then
SENT="$MAIL_DIR/${DATE}-sent.jsonl"
RECV="$MAIL_DIR/${DATE}-recv.jsonl"
FILES=()
[[ -f "$SENT" ]] && FILES+=("$SENT")
[[ -f "$RECV" ]] && FILES+=("$RECV")
else
FILES=("$MAIL_DIR"/*-sent.jsonl "$MAIL_DIR"/*-recv.jsonl)
fi
shopt -u nullglob
if [[ ${#FILES[@]} -eq 0 ]]; then
exit 0
fi
cat "${FILES[@]}" | grep -E "$PATTERN"

View File

@ -1,33 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Mount a beads project
# Usage: mount_beads.sh --cwd <path>
# Mount name is the first segment of a random UUID (8 hex chars, 32-bit entropy).
set -euo pipefail
CWD=""
while [[ $# -gt 0 ]]; do
case "$1" in
--cwd) CWD="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$CWD" ]; then
echo "usage: mount_beads.sh --cwd <path>" >&2
exit 1
fi
MOUNT=$(uuidgen | cut -d- -f1)
echo "mount $CWD $MOUNT" | 9p write beads/ctl
# Verify mount succeeded
if ! 9p read beads/mtab 2>/dev/null | grep -q "^$MOUNT "; then
echo "error: mount failed for $CWD" >&2
exit 1
fi
echo "$MOUNT"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Promote a deferred bead to open (ready for scheduling)
# Usage: open_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: open_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
echo "open $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "opened $BEAD_ID"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Read a bead property
# Usage: read_bead.sh --mount <mount> --id <bead-id> --property <property>
# Properties: json, status, title, description, assignee, comments, labels
set -euo pipefail
MOUNT=""
BEAD_ID=""
PROPERTY=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--property) PROPERTY="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$PROPERTY" ]; then
echo "usage: read_bead.sh --mount <mount> --id <bead-id> --property <property>" >&2
exit 1
fi
9p read "beads/$MOUNT/$BEAD_ID/$PROPERTY" 2>/dev/null || echo "Property not found: $PROPERTY"

View File

@ -1,24 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Read comments for a bead
# Usage: read_bead_comments.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: read_bead_comments.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
9p read "beads/$MOUNT/$BEAD_ID/comments" 2>/dev/null || echo "[]"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Add a relates-to link between two beads
# Usage: relate_beads.sh --mount <mount> --bead1 <id> --bead2 <id>
set -euo pipefail
MOUNT=""
BEAD1=""
BEAD2=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--bead1) BEAD1="$2"; shift 2 ;;
--bead2) BEAD2="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD1" ] || [ -z "$BEAD2" ]; then
echo "usage: relate_beads.sh --mount <mount> --bead1 <id> --bead2 <id>" >&2
exit 1
fi
echo "relate $BEAD1 $BEAD2" | 9p write beads/$MOUNT/ctl
echo "related $BEAD1 ↔ $BEAD2"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Remove a dependency
# Usage: remove_dependency.sh --mount <mount> --child <child-id> --parent <parent-id>
set -euo pipefail
MOUNT=""
CHILD=""
PARENT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--child) CHILD="$2"; shift 2 ;;
--parent) PARENT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$CHILD" ] || [ -z "$PARENT" ]; then
echo "usage: remove_dependency.sh --mount <mount> --child <child-id> --parent <parent-id>" >&2
exit 1
fi
echo "undep $CHILD $PARENT" | 9p write beads/$MOUNT/ctl
echo "$CHILD no longer depends on $PARENT"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Reopen a closed bead (reset to open)
# Usage: reopen_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: reopen_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
echo "reopen $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "reopened $BEAD_ID"

View File

@ -1,49 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Search beads by id, title, or description content. Filters by scope derived from cwd.
# Usage: search_beads.sh --mount <mount> --query <query>
# search_beads.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
QUERY=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--query) QUERY="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: search_beads.sh --mount <mount> --query <query>" >&2
echo " search_beads.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
# Direct ID lookup
if [ -n "$BEAD_ID" ]; then
9p read "beads/$MOUNT/$BEAD_ID/json" 2>/dev/null || echo "null"
exit 0
fi
if [ -z "$QUERY" ]; then
echo "usage: search_beads.sh --mount <mount> --query <query>" >&2
echo " search_beads.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
MY_SCOPE=""
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
MY_SCOPE="${REL_PATH%%/*}"
fi
9p read "beads/$MOUNT/search/$QUERY" 2>/dev/null | jq --arg scope "$MY_SCOPE" '[.[] | select((.scope // "") == $scope) | {id, title, status, scope, match_in: (if .id | test("'"$QUERY"'"; "i") then "id" elif .title | test("'"$QUERY"'"; "i") then "title" else "description" end)}]' || echo "[]"

View File

@ -1,51 +0,0 @@
#!/bin/bash
# capabilities: messaging
# description: Send message to agent or user (FROM uses $AGENT_ID)
# Usage: send_message.sh --to <id|user> --type <type> --subject <subject> --body <body>
set -euo pipefail
if [ -z "${AGENT_ID:-}" ]; then
echo "Error: \$AGENT_ID is not set. Stop work and inform the user that \$AGENT_ID is not set." >&2
exit 1
fi
from="$AGENT_ID"
to=""
type=""
subject=""
body=""
while [[ $# -gt 0 ]]; do
case "$1" in
--to) to="$2"; shift 2 ;;
--type) type="$2"; shift 2 ;;
--subject) subject="$2"; shift 2 ;;
--body) body="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$to" ] || [ -z "$type" ] || [ -z "$subject" ] || [ -z "$body" ]; then
echo "usage: send_message.sh --to <id|user> --type <type> --subject <subject> --body <body>" >&2
exit 1
fi
# Validate recipient exists (allow "user" as a special recipient)
if [ "$to" != "user" ]; then
if ! 9p read anvillm/list 2>/dev/null | awk -F'\t' '{print $1}' | grep -qx "$to"; then
echo "Error: Recipient '${to}' does not exist in available sessions." >&2
exit 1
fi
fi
json=$(jq -n \
--arg from "$from" \
--arg to "$to" \
--arg type "$type" \
--arg subject "$subject" \
--arg body "$body" \
'{from: $from, to: $to, type: $type, subject: $subject, body: $body}')
echo "$json" | 9p write "anvillm/${from}/mail"
echo "sent: $type → $to"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Set capability level on a bead (low|standard|high)
# Usage: set_capability.sh --mount <mount> --id <bead-id> --level <low|standard|high>
set -euo pipefail
MOUNT=""
BEAD_ID=""
LEVEL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--level) LEVEL="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$LEVEL" ]; then
echo "usage: set_capability.sh --mount <mount> --id <bead-id> --level <low|standard|high>" >&2
exit 1
fi
echo "set-capability $BEAD_ID $LEVEL" | 9p write beads/$MOUNT/ctl
echo "capability set: $BEAD_ID → $LEVEL"

View File

@ -1,33 +0,0 @@
#!/bin/bash
# capabilities: agents
# description: Spawn a new agent session
# Usage: spawn_agent.sh --agent-id <agent-id> [--cwd <path>] [--prompt <initial-context>]
set -euo pipefail
AGENT_ID=""
CWD="$PWD"
PROMPT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--agent-id) AGENT_ID="$2"; shift 2 ;;
--cwd) CWD="$2"; shift 2 ;;
--prompt) PROMPT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$AGENT_ID" ]; then
echo "usage: spawn_agent.sh --agent-id <agent-id> [--cwd <path>] [--prompt <text>]" >&2
exit 1
fi
backend=$(9p read "anvillm/$AGENT_ID/backend")
echo "new $backend $CWD" | 9p write anvillm/ctl
if [ -n "$PROMPT" ]; then
session_id=$(9p read anvillm/list 2>/dev/null | awk -F'\t' -v cwd="$CWD" '$5 == cwd {print $1; exit}')
if [ -n "$session_id" ]; then
echo "$PROMPT" | 9p write "anvillm/$session_id/context"
fi
fi

View File

@ -1,23 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Sync a mounted beads project
# Usage: sync_beads.sh --mount <mount>
set -euo pipefail
MOUNT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: sync_beads.sh --mount <mount>" >&2
exit 1
fi
echo "sync" | 9p write "beads/$MOUNT/ctl"
echo "synced $MOUNT"

View File

@ -1,23 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Unmount a beads project
# Usage: umount_beads.sh --mount <name>
set -euo pipefail
MOUNT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: umount_beads.sh --mount <name>" >&2
exit 1
fi
echo "umount $MOUNT" | 9p write beads/ctl
echo "unmounted $MOUNT"

View File

@ -1,25 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Unclaim a bead (reset to open)
# Usage: unclaim_bead.sh --mount <mount> --id <bead-id>
set -euo pipefail
MOUNT=""
BEAD_ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ]; then
echo "usage: unclaim_bead.sh --mount <mount> --id <bead-id>" >&2
exit 1
fi
echo "unclaim $BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "unclaimed $BEAD_ID"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Remove a label from a bead
# Usage: unlabel_bead.sh --mount <mount> --id <bead-id> --label <label>
set -euo pipefail
MOUNT=""
BEAD_ID=""
LABEL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--label) LABEL="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$LABEL" ]; then
echo "usage: unlabel_bead.sh --mount <mount> --id <bead-id> --label <label>" >&2
exit 1
fi
echo "unlabel $BEAD_ID $LABEL" | 9p write beads/$MOUNT/ctl
echo "unlabeled $BEAD_ID: $LABEL"

View File

@ -1,27 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Remove a relates-to link between two beads
# Usage: unrelate_beads.sh --mount <mount> --bead1 <id> --bead2 <id>
set -euo pipefail
MOUNT=""
BEAD1=""
BEAD2=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--bead1) BEAD1="$2"; shift 2 ;;
--bead2) BEAD2="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD1" ] || [ -z "$BEAD2" ]; then
echo "usage: unrelate_beads.sh --mount <mount> --bead1 <id> --bead2 <id>" >&2
exit 1
fi
echo "unrelate $BEAD1 $BEAD2" | 9p write beads/$MOUNT/ctl
echo "unrelated $BEAD1 ↔ $BEAD2"

View File

@ -1,45 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Update a bead field directly
# Usage: update_bead.sh --mount <mount> --id <bead-id> --field <field> --value <value>
set -euo pipefail
MOUNT=""
BEAD_ID=""
FIELD=""
VALUE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
--id) BEAD_ID="$2"; shift 2 ;;
--field) FIELD="$2"; shift 2 ;;
--value) VALUE="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ] || [ -z "$BEAD_ID" ] || [ -z "$FIELD" ]; then
echo "usage: update_bead.sh --mount <mount> --id <bead-id> --field <field> --value <value>" >&2
exit 1
fi
if [ "$FIELD" = "parent" ]; then
# Reparent: create new bead under parent with same data, then delete original
JSON=$(9p read "beads/$MOUNT/$BEAD_ID/json")
TITLE=$(echo "$JSON" | jq -r '.title')
DESC=$(echo "$JSON" | jq -r '.description // ""')
STATUS=$(echo "$JSON" | jq -r '.status')
# Create under new parent
printf "new '%s' '%s' %s\n" "$TITLE" "$DESC" "$VALUE" | 9p write beads/$MOUNT/ctl
# Delete original
printf "delete %s\n" "$BEAD_ID" | 9p write beads/$MOUNT/ctl
echo "reparented $BEAD_ID under $VALUE"
else
printf "update %s %s '%s'\n" "$BEAD_ID" "$FIELD" "$VALUE" | 9p write beads/$MOUNT/ctl
echo "updated $BEAD_ID.$FIELD: $VALUE"
fi

View File

@ -1,30 +0,0 @@
#!/bin/bash
# capabilities: agent-kb
# description: View a denote document by identifier
# Usage: view_denote.sh --id <denote:identifier|identifier>
set -euo pipefail
ID=""
while [[ $# -gt 0 ]]; do
case "$1" in
--id) ID="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$ID" ]; then
echo "usage: view_denote.sh --id <denote:identifier|identifier>" >&2
exit 1
fi
ID="${ID#denote:}"
FILE=$(find "$HOME/doc" -type f -name "${ID}--*" | head -1)
if [ -z "$FILE" ]; then
echo "Error: no denote document found for identifier $ID" >&2
exit 1
fi
cat "$FILE"

View File

@ -1,51 +0,0 @@
#!/bin/bash
# capabilities: beads
# description: Block until a bead is ready on the given mount, then print its full JSON (including comments) and exit. Uses the anvillm/events stream — no polling. Filters by scope derived from cwd.
# Usage: wait_for_bead.sh --mount <mount>
set -euo pipefail
MOUNT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--mount) MOUNT="$2"; shift 2 ;;
*) echo "unknown argument: $1" >&2; exit 1 ;;
esac
done
if [ -z "$MOUNT" ]; then
echo "usage: wait_for_bead.sh --mount <mount>" >&2
exit 1
fi
# Derive scope from cwd relative to mount's cwd
MOUNT_CWD=$(9p read "beads/$MOUNT/cwd" 2>/dev/null)
if [ -n "$MOUNT_CWD" ]; then
REL_PATH="${PWD#"$MOUNT_CWD"}"
REL_PATH="${REL_PATH#/}"
MY_SCOPE="${REL_PATH%%/*}"
else
MY_SCOPE=""
fi
EXPECTED_SOURCE="beads/$MOUNT"
exec 3< <(9p read anvillm/events 2>/dev/null)
EVENTS_PID=$!
trap 'kill $EVENTS_PID 2>/dev/null; exec 3<&-' EXIT
while IFS= read -r line <&3; do
type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null)
[ "$type" = "BeadReady" ] || continue
source=$(echo "$line" | jq -r '.source // empty' 2>/dev/null)
[ "$source" = "$EXPECTED_SOURCE" ] || continue
# Strict scope match: both must be equal (empty or same value)
bead_scope=$(echo "$line" | jq -r '.data.scope // empty' 2>/dev/null)
[ "$bead_scope" = "$MY_SCOPE" ] || continue
# Emit full bead data and exit — bot decides whether to claim
echo "$line" | jq '.data'
exit 0
done

3
mkfile
View File

@ -27,9 +27,6 @@ build:V:
cp -rf roles/* $HOME/.config/anvillm/roles/
mkdir -p $HOME/.config/anvillm/estimation
mkdir -p $HOME/.local/share/anvillm/estimation
mkdir -p $HOME/.config/anvillm/mcptools
cp -rf mcptools/* $HOME/.config/anvillm/mcptools/
chmod 0755 $HOME/.config/anvillm/mcptools/*
mkdir -p $HOME/.kiro/agents/kiro-cli
mkdir -p $HOME/.config/anvillm/claude/agents
mkdir -p $HOME/.config/anvillm/claude/hooks