
Agentation
- 25 installs
- 40 repo stars
- Updated August 4, 2026
- akillness/skills-template
agentation is a skill that captures exact rendered-UI feedback as selectors and structured packets and hands it to a coding agent.
About
This skill captures rendered-UI feedback and encodes it as structured packets with selectors, element paths, and bounding boxes. A developer uses it when a human reviewer needs to point at a real UI element and hand a precise fix packet to a coding agent. It supports copy-paste review, an MCP-backed synced watch loop, and self-driving critique modes.
- Captures exact UI feedback as selectors, element paths, and bounding boxes
- Bridges browser annotations into Claude Code, Codex, Gemini CLI, or OpenCode
- Offers copy-paste, synced watch-loop, and self-driving critique modes
Agentation by the numbers
- 25 all-time installs (skills.sh)
- Ranked #1,346 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
agentation capabilities & compatibility
- Capabilities
- ui feedback capture · browser annotation · agent handoff
- Works with
- chrome
- Use cases
- ui design · web design · code review
- Pricing
- Free
What agentation says it does
`agentation` is the **rendered-UI feedback bridge** in this repo.
a human reviewer pointing at a real UI element instead of describing it vaguely
npx skills add https://github.com/akillness/skills-template --skill agentationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 25 |
|---|---|
| repo stars | ★ 40 |
| Last updated | August 4, 2026 |
| Repository | akillness/skills-template ↗ |
What it does
Capture exact rendered-UI feedback as structured packets and hand them to a coding agent to fix.
Who is it for?
Attaching precise human UI feedback to elements and routing it to a coding agent
Skip if: Fresh-session browser verification (use agent-browser) or plan/diff approval (use plannotator)
When should I use this skill?
A human needs to click the actual UI and pass a structured fix packet to the agent
What you get
A structured annotation packet with exact selectors that a coding agent can act on precisely.
- structured annotation packet
- MCP bridge for supported agents
By the numbers
- 4 annotation modes (copy-paste, synced watch, self-driving, platform setup)
- 6-step core loop
Files
agentation
agentation is the rendered-UI feedback bridge in this repo.
Use it when a human needs to click the actual UI, attach feedback to the exact element or region they mean, and pass a structured packet to the coding agent. The main job is annotation routing: choose the right annotation mode, capture precise evidence, then hand the fix loop to the right adjacent skill or agent runtime.
When to use this skill
Use agentation when the task needs one or more of these:
- a human reviewer pointing at a real UI element instead of describing it vaguely
- structured feedback packets with selectors, element paths, bounding boxes, or copied markdown
- a local copy-paste review loop between a browser and a coding agent
- an MCP-backed sync/watch loop where new annotations flow into the agent context automatically
- a self-driving critique/fix loop that still starts from rendered UI evidence
- platform setup for passing pending UI annotations into Claude Code, Codex, Gemini CLI, or OpenCode
Do not use agentation by default for:
- fresh-session browser verification or deterministic regression checks →
agent-browser - running-browser, logged-in, or extension-dependent browser reuse →
playwriter - plan review, diff approval, or visual sign-off on a proposed artifact →
plannotator - generic design-system, accessibility, or heuristic audits without a concrete rendered UI packet
Quick routing rule
| If the job needs... | Use |
|---|---|
| Human clicks the UI and leaves exact feedback for the agent | agentation |
| Browser verification in a clean repeatable session | agent-browser |
| The user's already-open browser, cookies, or logged-in tabs | playwriter |
| Review or approval of a plan/diff before execution | plannotator |
Instructions
Step 1: Choose the right annotation mode
Pick one mode before touching setup details:
| Mode | Use when | Output |
|---|---|---|
| Copy-paste review | One reviewer wants to annotate UI and paste the packet into chat | a structured markdown packet |
| Synced watch loop | New annotations should appear in the agent workflow automatically | pending-annotation queue + loop |
| Self-driving critique | An agent/browser loop will generate or consume annotations repeatedly | a review/fix loop packet |
| Platform setup | The core problem is wiring the annotation bridge into Claude/Codex/Gemini/OpenCode | a setup checklist and config target |
If the task is really “test the website” or “drive the logged-in browser,” route out first and only come back to agentation if exact human UI feedback is the missing piece.
Step 2: Keep the browser boundary explicit
agentation does not replace the browser runtime choice.
- Use
agent-browserwhen you want a clean disposable verification browser. - Use
playwriterwhen you must reuse the user's real browser session. - Use
agentationonce there is a rendered page that a human or loop should annotate precisely.
Step 3: Follow the core loop
1. Prepare the rendered UI
- Choose the correct browser/runtime skill first if needed.
2. Add the Agentation toolbar to the app in development. 3. Pick the annotation mode: copy-paste, watch loop, self-driving, or setup. 4. Capture one concrete UI packet. 5. Hand the packet to the coding agent. 6. Re-verify after the fix using the same review lane.
Step 4: Use the fastest safe install path
For most setups, the practical order is:
# React toolbar
npm install agentation -D
# MCP bridge / auto-registration for supported agents
npx add-mcp "npx -y agentation-mcp server"
# verify the bridge
npx agentation-mcp doctorClaude Code users can also install the upstream official skill when that is the simplest way to bootstrap the experience:
npx skills add benjitaylor/agentation -g
# then use /agentation in Claude CodeStep 5: Use a minimal toolbar integration first
Start with the smallest useful embed:
import { Agentation } from 'agentation';
function App() {
return (
<>
<YourApp />
{process.env.NODE_ENV === 'development' && <Agentation />}
</>
)
}Only add endpoint, callbacks, or webhook behavior when the chosen mode actually needs them.
Step 6: Choose the right handoff pattern
A. Copy-paste review
Use when a human is actively reviewing the page and pasting the packet into an agent chat.
Good for:
- quick bug/UI polish rounds
- one-off targeted fixes
- low-setup collaboration
B. Synced watch loop
Use when the agent should poll or ingest pending annotations continuously.
Good for:
- repeated QA/fix passes
- designer ↔ agent loops
- local review queues during active frontend work
Use the bundled verification script before trusting the loop:
bash .agent-skills/agentation/scripts/verify-loop.shC. Self-driving critique
Use when an agent/browser loop is reviewing UI repeatedly and agentation is the structured feedback packet, not the browser runtime itself.
Typical shape:
- browser tool captures current state
agentationencodes concrete feedback targets- coding agent applies the fix
- browser tool re-checks the result
Step 7: Keep platform setup narrow
When the request is really about platform wiring, answer only:
- where the config lives
- how
agentation-mcpis registered - how pending annotations enter the agent loop
- how to verify the setup
Push the platform-specific config blocks into the references instead of bloating the main workflow.
Scripts
Prefer the bundled scripts before retyping long commands:
| Script | Purpose |
|---|---|
scripts/setup-agentation-mcp.sh | Register the MCP bridge for supported agents |
scripts/verify-loop.sh | Validate annotation queue / ACK → RESOLVE style watch-loop behavior |
Examples
Example 1: Human reviewer wants exact UI feedback
- Prompt: "I can point at the broken checkout button, but I don't want to describe selectors manually."
- Expected behavior: choose
agentation, recommend copy-paste review or sync mode, keep browser-runtime choice separate.
Example 2: Browser verification is the real job
- Prompt: "Run a repeatable headless UI regression check and compare the results."
- Expected behavior: route to
agent-browser, notagentation, unless human annotation becomes a follow-up step.
Example 3: Logged-in browser reuse
- Prompt: "Use the browser I'm already signed into and let me annotate a billing page issue."
- Expected behavior: route the browser runtime to
playwriter, then useagentationfor the annotation packet.
Example 4: Planning review, not UI review
- Prompt: "Open the generated plan in a browser so I can approve or reject steps before coding starts."
- Expected behavior: route to
plannotator, because the artifact is a plan/diff rather than a rendered UI issue.
Best practices
1. Pick the browser/runtime lane first; agentation is the feedback bridge, not every browser tool. 2. Prefer one annotation mode at a time instead of mixing copy-paste, watch loop, and platform setup in a single answer. 3. Keep the first integration minimal; only add hooks, callbacks, or webhooks when the workflow needs them. 4. Re-verify after fixes with the same review lane that produced the annotation. 5. Treat exact UI feedback as the deliverable — not a giant dump of install permutations. 6. Route out aggressively when the task is really plan review, fresh-browser verification, or running-browser reuse.
References
Deep-dive docs in this skill:
- modes-and-routing
- platform-setup-and-hooks
- watch-loop-and-self-driving
Primary sources:
- https://github.com/benjitaylor/agentation
- https://agentation.com
- https://www.npmjs.com/package/agentation
- https://www.npmjs.com/package/agentation-mcp
Metadata
- Version: 1.1.0
- Last updated: 2026-04-15
- Scope: exact rendered-UI feedback packets, watch loops, and platform handoff for coding agents
{
"skill_name": "agentation",
"evals": [
{
"id": 1,
"prompt": "I can click the broken CTA in the running app, leave a note, and I want the agent to patch the exact component without guessing which button I mean.",
"expected_output": "Chooses agentation as the UI annotation bridge, recommends a copy-paste or synced review mode, and keeps browser-runtime choice separate.",
"assertions": [
"Selects agentation for exact rendered-UI feedback",
"Mentions structured annotation packets or exact UI targeting",
"Does not misroute the task to plannotator as the primary skill"
]
},
{
"id": 2,
"prompt": "Run a repeatable headless checkout verification and compare the result in a clean browser session.",
"expected_output": "Routes away from agentation to agent-browser because deterministic fresh-session verification is the real job.",
"assertions": [
"Routes to agent-browser or an equivalent fresh-session browser verifier",
"Explains that agentation is not the primary tool for deterministic browser verification"
]
},
{
"id": 3,
"prompt": "Wire the annotation queue into Claude Code so pending UI notes show up automatically every time I send a message.",
"expected_output": "Chooses agentation platform setup mode, mentions MCP registration plus the Claude hook/injection path, and includes verification guidance.",
"assertions": [
"Selects agentation platform setup or watch-loop mode",
"Mentions MCP registration or agentation-mcp",
"Mentions verifying the setup before trusting the loop"
]
},
{
"id": 4,
"prompt": "Open the proposed implementation plan in a browser so I can approve or reject changes before coding starts.",
"expected_output": "Routes away from agentation to plannotator because the review target is a plan/diff rather than a rendered UI issue.",
"assertions": [
"Routes to plannotator or equivalent plan review skill",
"Explains that agentation is for rendered UI feedback, not plan approval"
]
}
]
}
Agentation Modes and Routing
What agentation owns
agentation owns the moment when a rendered UI issue must become a precise feedback packet for an agent:
- exact element targeting
- structured annotation output
- human ↔ agent feedback handoff
- watch-loop queue behavior
It is not the default browser runtime and it is not a generic review tool.
Mode selection
1. Copy-paste review
Use when a human reviewer is present and wants to paste a packet into chat.
Choose this when:
- setup should stay light
- the review is synchronous
- the agent only needs one or a few targeted fixes
2. Synced watch loop
Use when annotations should flow into the agent context automatically.
Choose this when:
- the frontend is under active iteration
- multiple annotations may arrive over time
- ACK / RESOLVE queue behavior matters
3. Self-driving critique
Use when an agent/browser loop is repeatedly checking UI output and agentation is the structured review packet.
Choose this when:
- the loop already has a browser runtime
- the system needs repeatable rendered-UI evidence
- the coding agent will fix and re-check repeatedly
4. Platform setup
Use when the real task is wiring the bridge into Claude Code, Codex, Gemini CLI, or OpenCode.
Choose this when:
- the user already understands the UI-review job
- the blocker is MCP or hook configuration
- the next step is verifying that pending annotations enter the agent context
Route-outs
Route to agent-browser
Use agent-browser when the real need is:
- clean disposable browser sessions
- deterministic refs / replayable checks
- headless or CI-style verification
- browser automation even without a human reviewer
Route to playwriter
Use playwriter when the real need is:
- the browser the user already has open
- existing cookies, SSO, extensions, or passkeys
- shared human/agent tab continuity
Route to plannotator
Use plannotator when the review target is:
- a plan
- a diff
- an execution checklist
- an approval/rejection workflow before implementation
Minimal React integration
import { Agentation } from 'agentation';
function App() {
return (
<>
<YourApp />
{process.env.NODE_ENV === 'development' && <Agentation />}
</>
)
}Only add endpoint, callbacks, session wiring, or webhook behavior after the mode is chosen.
Agentation Platform Setup and Hooks
Fastest common path
npm install agentation -D
npx add-mcp "npx -y agentation-mcp server"
npx agentation-mcp doctorThis covers the common case: install the toolbar, register the MCP bridge, then verify the bridge before assuming the queue works.
Claude Code
Upstream official skill path
npx skills add benjitaylor/agentation -g
# then use /agentationDirect MCP registration
claude mcp add agentation -- npx -y agentation-mcp serverHook use case
If the goal is to inject pending annotations into each prompt, configure a UserPromptSubmit hook in the relevant Claude settings file. Keep the hook command small and focused on fetching pending annotations rather than embedding large formatting logic in the hook itself.
Codex CLI
- Register the MCP bridge in Codex config or use
add-mcpwhen available. - Keep the setup answer focused on where the config lives, how the bridge is registered, and how to verify it.
- Do not turn the setup path into a generic browser-automation answer.
Gemini CLI
- Register the MCP bridge in Gemini config or via
add-mcp. - Use hook/post-agent style configuration only when pending annotation injection is the explicit requirement.
OpenCode
- Register the MCP server in the platform's MCP config.
- OpenCode usually needs less hook ceremony; prefer the simplest working registration.
Verification checklist
1. Toolbar renders in development. 2. agentation-mcp server starts successfully. 3. npx agentation-mcp doctor passes. 4. A new annotation appears in the queue. 5. The agent loop can see or consume the pending annotation. 6. ACK / resolve behavior works before real work starts.
Pitfalls
- Avoid hard-coding platform-specific setup for every agent into the main
SKILL.md. - Do not present hooks as mandatory when copy-paste review is enough.
- Keep version-sensitive config snippets in references so the main skill stays durable.
Agentation Watch Loop and Self-Driving Patterns
Watch-loop pattern
Use the watch loop when new annotations should enter the agent workflow automatically instead of being pasted manually.
Typical shape: 1. Human annotates the rendered page. 2. agentation-mcp exposes the pending queue. 3. Agent loop reads pending annotations. 4. Agent fixes the issue. 5. Queue item is ACKed / resolved. 6. Browser is re-checked.
Before trusting the loop, run:
bash .agent-skills/agentation/scripts/verify-loop.shSelf-driving critique pattern
Use this when the browser-review system is iterative and structured feedback needs to survive across cycles.
Typical shape:
- choose the browser runtime first (
agent-browserorplaywriter) - capture rendered state
- turn the issue into an
agentationpacket - hand the packet to the coding agent
- re-run the browser check
- repeat only while the same failure class persists
When not to use a loop
Do not default to a watch loop when:
- one human review round is enough
- the team has not verified queue visibility yet
- the actual blocker is browser setup, not annotation flow
- the task is really plan approval or pure automation verification
Good outputs from this skill
- one precise UI feedback packet
- one verified watch-loop setup checklist
- one explicit route-out to the correct browser or review neighbor
Common mistakes
- treating
agentationas the browser runtime - mixing plan review, browser runtime choice, and annotation capture in one answer
- skipping post-fix verification
- assuming self-driving critique means no human or browser evidence is needed
#!/usr/bin/env bash
# setup-agentation-mcp.sh — Register agentation MCP server for all AI agent platforms
#
# Usage:
# bash setup-agentation-mcp.sh # all platforms
# bash setup-agentation-mcp.sh --claude # Claude Code only
# bash setup-agentation-mcp.sh --codex # Codex CLI only
# bash setup-agentation-mcp.sh --gemini # Gemini CLI only
# bash setup-agentation-mcp.sh --opencode # OpenCode only
# bash setup-agentation-mcp.sh --all # all platforms (explicit)
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info() { echo -e "${BLUE}ℹ $*${NC}"; }
ok() { echo -e "${GREEN}✅ $*${NC}"; }
warn() { echo -e "${YELLOW}⚠ $*${NC}"; }
err() { echo -e "${RED}✗ $*${NC}" >&2; }
# ─── Argument parsing ────────────────────────────────────────────────────────
SETUP_CLAUDE=false
SETUP_CODEX=false
SETUP_GEMINI=false
SETUP_OPENCODE=false
while [[ $# -gt 0 ]]; do
case "$1" in
--claude) SETUP_CLAUDE=true ;;
--codex) SETUP_CODEX=true ;;
--gemini) SETUP_GEMINI=true ;;
--opencode) SETUP_OPENCODE=true ;;
--all) SETUP_CLAUDE=true; SETUP_CODEX=true; SETUP_GEMINI=true; SETUP_OPENCODE=true ;;
*) warn "Unknown flag: $1" ;;
esac
shift
done
# Default: all platforms
if [[ "$SETUP_CLAUDE$SETUP_CODEX$SETUP_GEMINI$SETUP_OPENCODE" == "falsefalsefalsefalse" ]]; then
SETUP_CLAUDE=true; SETUP_CODEX=true; SETUP_GEMINI=true; SETUP_OPENCODE=true
fi
echo "╔══════════════════════════════════════════╗"
echo "║ agentation MCP Setup ║"
echo "╚══════════════════════════════════════════╝"
echo ""
# ─── Claude Code (~/.claude/claude_desktop_config.json) ───────────────────
if [[ "$SETUP_CLAUDE" == "true" ]]; then
info "Setting up Claude Code..."
CLAUDE_DIR="$HOME/.claude"
CLAUDE_CFG="$CLAUDE_DIR/claude_desktop_config.json"
mkdir -p "$CLAUDE_DIR"
MCP_JSON='{"command":"npx","args":["-y","agentation-mcp","server"]}'
if [[ -f "$CLAUDE_CFG" ]]; then
if command -v jq &>/dev/null; then
MERGED=$(jq --argjson entry "$MCP_JSON" '.mcpServers.agentation = $entry' "$CLAUDE_CFG" 2>/dev/null)
if [[ -n "$MERGED" ]]; then
echo "$MERGED" > "$CLAUDE_CFG"
ok "Claude Code: merged into $CLAUDE_CFG"
else
warn "Claude Code: jq merge failed — add manually"
fi
else
warn "Claude Code: jq not found — add manually to $CLAUDE_CFG:"
echo ' "mcpServers": { "agentation": { "command": "npx", "args": ["-y", "agentation-mcp", "server"] } }'
fi
else
cat > "$CLAUDE_CFG" <<'EOF'
{
"mcpServers": {
"agentation": {
"command": "npx",
"args": ["-y", "agentation-mcp", "server"]
}
}
}
EOF
ok "Claude Code: created $CLAUDE_CFG"
fi
echo ""
fi
# ─── Codex CLI (~/.codex/config.toml) ─────────────────────────────────────
if [[ "$SETUP_CODEX" == "true" ]]; then
info "Setting up Codex CLI..."
CODEX_DIR="$HOME/.codex"
CODEX_CFG="$CODEX_DIR/config.toml"
mkdir -p "$CODEX_DIR"
CODEX_ENTRY=$'\n# agentation MCP Server\n[[mcp_servers]]\nname = "agentation"\ncommand = "npx"\nargs = ["-y", "agentation-mcp", "server"]\n'
if [[ -f "$CODEX_CFG" ]]; then
if grep -q '"agentation"\|name = "agentation"' "$CODEX_CFG" 2>/dev/null; then
warn "Codex CLI: agentation already in $CODEX_CFG — skipping"
else
printf '%s' "$CODEX_ENTRY" >> "$CODEX_CFG"
ok "Codex CLI: appended to $CODEX_CFG"
fi
else
printf '%s' "$CODEX_ENTRY" > "$CODEX_CFG"
ok "Codex CLI: created $CODEX_CFG"
fi
echo ""
fi
# ─── Gemini CLI (~/.gemini/settings.json) ─────────────────────────────────
if [[ "$SETUP_GEMINI" == "true" ]]; then
info "Setting up Gemini CLI..."
GEMINI_DIR="$HOME/.gemini"
GEMINI_CFG="$GEMINI_DIR/settings.json"
mkdir -p "$GEMINI_DIR"
MCP_JSON='{"command":"npx","args":["-y","agentation-mcp","server"]}'
if [[ -f "$GEMINI_CFG" ]]; then
if command -v jq &>/dev/null; then
MERGED=$(jq --argjson entry "$MCP_JSON" '.mcpServers.agentation = $entry' "$GEMINI_CFG" 2>/dev/null)
if [[ -n "$MERGED" ]]; then
echo "$MERGED" > "$GEMINI_CFG"
ok "Gemini CLI: merged into $GEMINI_CFG"
else
warn "Gemini CLI: jq merge failed — add manually"
fi
else
warn "Gemini CLI: jq not found — add manually to $GEMINI_CFG:"
echo ' "mcpServers": { "agentation": { "command": "npx", "args": ["-y", "agentation-mcp", "server"] } }'
fi
else
cat > "$GEMINI_CFG" <<'EOF'
{
"mcpServers": {
"agentation": {
"command": "npx",
"args": ["-y", "agentation-mcp", "server"]
}
}
}
EOF
ok "Gemini CLI: created $GEMINI_CFG"
fi
echo ""
fi
# ─── OpenCode (~/.config/opencode/opencode.json) ──────────────────────────
if [[ "$SETUP_OPENCODE" == "true" ]]; then
info "Setting up OpenCode..."
OC_DIR="$HOME/.config/opencode"
OC_CFG="$OC_DIR/opencode.json"
mkdir -p "$OC_DIR"
MCP_ENTRY='{"type":"local","command":["npx","-y","agentation-mcp","server"]}'
if [[ -f "$OC_CFG" ]]; then
if command -v jq &>/dev/null; then
MERGED=$(jq --argjson entry "$MCP_ENTRY" '.mcp.agentation = $entry' "$OC_CFG" 2>/dev/null)
if [[ -n "$MERGED" ]]; then
echo "$MERGED" > "$OC_CFG"
ok "OpenCode: merged into $OC_CFG"
else
warn "OpenCode: jq merge failed — add manually"
fi
else
warn "OpenCode: jq not found — add manually to $OC_CFG:"
echo ' "mcp": { "agentation": { "type": "local", "command": ["npx", "-y", "agentation-mcp", "server"] } }'
fi
else
cat > "$OC_CFG" <<'EOF'
{
"mcp": {
"agentation": {
"type": "local",
"command": ["npx", "-y", "agentation-mcp", "server"]
}
}
}
EOF
ok "OpenCode: created $OC_CFG"
fi
echo ""
fi
# ─── Done ─────────────────────────────────────────────────────────────────
echo "╔══════════════════════════════════════════╗"
echo "║ Setup Complete ║"
echo "╚══════════════════════════════════════════╝"
echo ""
echo "Next steps:"
echo " 1. Restart your agent(s)"
echo " 2. Start agentation MCP server: npx agentation-mcp server"
echo " 3. Add to your app: import { Agentation } from 'agentation'"
echo " <Agentation endpoint=\"http://localhost:4747\" />"
echo ""
echo "Available MCP tools: agentation_watch_annotations, agentation_resolve, agentation_acknowledge, ..."
echo "Run 'npx agentation-mcp doctor' to verify."
#!/usr/bin/env bash
# verify-loop.sh — Integration test for agentation watch loop
# Tests: server health, annotation CRUD, ACK-RESOLVE cycle, error cases
# Usage: bash verify-loop.sh [--quick] (--quick skips phase 4 error tests)
set -euo pipefail
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
pass() { echo -e "${GREEN}PASS${NC} $*"; }
fail() { echo -e "${RED}FAIL${NC} $*"; FAILURES=$((FAILURES + 1)); }
info() { echo -e "${YELLOW}....${NC} $*"; }
FAILURES=0
BASE_URL="http://localhost:4747"
QUICK=false
[[ "${1:-}" == "--quick" ]] && QUICK=true
echo ""
echo "agentation Watch Loop — Integration Test"
echo "========================================="
echo ""
# ── Phase 1: Server Health ──────────────────────────────────────────────────
echo "Phase 1: Server Health"
echo "──────────────────────"
info "1a. Health check"
if curl -sf --connect-timeout 3 "${BASE_URL}/health" >/dev/null 2>&1; then
pass "GET /health — server reachable"
else
fail "GET /health — server not reachable. Start with: npx agentation-mcp server"
echo ""
echo "Cannot continue without server. Exiting."
exit 1
fi
info "1b. Status check"
STATUS=$(curl -sf "${BASE_URL}/status" 2>/dev/null || echo "")
if [[ -n "$STATUS" ]]; then
pass "GET /status — returns server metadata"
else
fail "GET /status — empty response"
fi
info "1c. Baseline pending check"
PENDING=$(curl -sf "${BASE_URL}/pending" 2>/dev/null || echo '{"count":-1}')
BASELINE_COUNT=$(echo "$PENDING" | python3 -c "import sys,json; print(json.load(sys.stdin).get('count',-1))" 2>/dev/null || echo -1)
if [[ "$BASELINE_COUNT" -ge 0 ]]; then
pass "GET /pending — baseline count: ${BASELINE_COUNT}"
else
fail "GET /pending — invalid response"
fi
echo ""
# ── Phase 2: Session & Annotation CRUD ──────────────────────────────────────
echo "Phase 2: Annotation CRUD"
echo "────────────────────────"
info "2a. Create session"
SESSION_RESP=$(curl -sf -X POST "${BASE_URL}/sessions" -H "Content-Type: application/json" -d '{}' 2>/dev/null || echo "")
SESSION_ID=$(echo "$SESSION_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "")
if [[ -n "$SESSION_ID" ]]; then
pass "POST /sessions — created session: ${SESSION_ID:0:12}..."
else
fail "POST /sessions — failed to create session"
echo "Cannot continue without session. Exiting."
exit 1
fi
info "2b. Create annotation"
ANN_RESP=$(curl -sf -X POST "${BASE_URL}/sessions/${SESSION_ID}/annotations" \
-H "Content-Type: application/json" \
-d "{\"comment\":\"Test: change button color\",\"element\":\"button\",\"elementPath\":\"body > main > button.cta\",\"x\":50,\"y\":100}" 2>/dev/null || echo "")
ANN_ID=$(echo "$ANN_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "")
if [[ -n "$ANN_ID" ]]; then
pass "POST annotation — created: ${ANN_ID:0:12}..."
else
fail "POST annotation — failed"
fi
info "2c. Verify pending count = 1"
P_COUNT=$(curl -sf "${BASE_URL}/sessions/${SESSION_ID}/pending" 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('count',0))" 2>/dev/null || echo 0)
if [[ "$P_COUNT" -eq 1 ]]; then
pass "GET /sessions/:id/pending — count: 1"
else
fail "GET /sessions/:id/pending — expected 1, got ${P_COUNT}"
fi
echo ""
# ── Phase 3: ACK-RESOLVE Cycle ──────────────────────────────────────────────
echo "Phase 3: ACK-RESOLVE Cycle"
echo "──────────────────────────"
info "3a. Acknowledge annotation"
ACK_RESP=$(curl -sf -X PATCH "${BASE_URL}/annotations/${ANN_ID}" \
-H "Content-Type: application/json" \
-d '{"status":"acknowledged"}' 2>/dev/null || echo "")
ACK_STATUS=$(echo "$ACK_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status',''))" 2>/dev/null || echo "")
if [[ "$ACK_STATUS" == "acknowledged" ]]; then
pass "PATCH acknowledged — status: acknowledged"
else
fail "PATCH acknowledged — expected 'acknowledged', got '${ACK_STATUS}'"
fi
info "3b. Resolve annotation"
RES_RESP=$(curl -sf -X PATCH "${BASE_URL}/annotations/${ANN_ID}" \
-H "Content-Type: application/json" \
-d '{"status":"resolved","resolution":"Changed button color to #3b82f6"}' 2>/dev/null || echo "")
RES_STATUS=$(echo "$RES_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status',''))" 2>/dev/null || echo "")
if [[ "$RES_STATUS" == "resolved" ]]; then
pass "PATCH resolved — status: resolved"
else
fail "PATCH resolved — expected 'resolved', got '${RES_STATUS}'"
fi
info "3c. Verify pending count = 0"
FINAL_COUNT=$(curl -sf "${BASE_URL}/sessions/${SESSION_ID}/pending" 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('count',0))" 2>/dev/null || echo -1)
if [[ "$FINAL_COUNT" -eq 0 ]]; then
pass "GET pending after resolve — count: 0 (all resolved)"
else
fail "GET pending after resolve — expected 0, got ${FINAL_COUNT}"
fi
echo ""
# ── Phase 4: Error Cases ────────────────────────────────────────────────────
if ! $QUICK; then
echo "Phase 4: Error Cases"
echo "────────────────────"
info "4a. Invalid annotation ID"
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" -X PATCH "${BASE_URL}/annotations/nonexistent-id-12345" \
-H "Content-Type: application/json" -d '{"status":"acknowledged"}' 2>/dev/null || echo "000")
if [[ "$HTTP_CODE" == "404" || "$HTTP_CODE" == "400" ]]; then
pass "Invalid ID — HTTP ${HTTP_CODE} (expected 4xx)"
else
fail "Invalid ID — expected 4xx, got HTTP ${HTTP_CODE}"
fi
info "4b. GET non-existent session"
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" "${BASE_URL}/sessions/nonexistent-session-12345" 2>/dev/null || echo "000")
if [[ "$HTTP_CODE" == "404" || "$HTTP_CODE" == "400" ]]; then
pass "Non-existent session — HTTP ${HTTP_CODE} (expected 4xx)"
else
fail "Non-existent session — expected 4xx, got HTTP ${HTTP_CODE}"
fi
echo ""
fi
# ── Summary ─────────────────────────────────────────────────────────────────
echo "========================================="
if [[ "$FAILURES" -eq 0 ]]; then
echo -e "${GREEN}ALL TESTS PASSED${NC}"
echo ""
echo "agentation watch loop is working correctly."
echo "MCP tool agentation_watch_annotations should function end-to-end."
else
echo -e "${RED}${FAILURES} TEST(S) FAILED${NC}"
echo ""
echo "Fix the issues above and re-run: bash verify-loop.sh"
fi
echo ""
exit $FAILURES
N:agentation D:"Capture exact rendered-UI feedback and hand it to an agent as selectors, element paths, and structured annotation packets. Use when a human needs to point at a real UI issue, run a sync/watch loop, or wire browser feedback into Claude Code, Codex, Gemini CLI, or OpenCode. Not for fresh-session browser verification (agent-browser), running-browser reuse (playwriter), or plan/diff approval (plannotator)." T:Read|Write|Bash|Grep|Glob P:planning-review/agentation G:ui-feedback|browser-annotation|visual-feedback|mcp|react|ai-agent|design-review|css-selectorRelated skills
FAQ
What does agentation produce?
A structured markdown packet with selectors, element paths, or bounding boxes that a coding agent can use.
How is it installed?
npm install agentation -D for the React toolbar, plus npx add-mcp for the MCP bridge to supported agents.