<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="/style.css">

    <title>What if you don't need MCP at all?</title>
    <meta name="description" content="Got Bash and some code interpreter? Skip MCP.">
    <meta property="og:title" content="What if you don't need MCP at all?">
    <meta property="og:type" content="article">
    <meta property="og:description" content="Got Bash and some code interpreter? Skip MCP.">
    <meta property="og:image" content="https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/media/header.png">
    <meta property="og:url" content="https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/">
    <meta name="twitter:card" content="summary_large_image">
    <meta property="twitter:domain" content="mariozechner.at">
    <meta property="twitter:url" content="https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/">
    <meta name="twitter:title" content="What if you don't need MCP at all?">
    <meta name="twitter:description" content="Got Bash and some code interpreter? Skip MCP.">
    <meta name="twitter:image" content="https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/media/header.png">

{ Mario Zechner }

                    developer • coach • speaker

            <theme-toggle class="mb-auto ml-auto"></theme-toggle>

<color-band class="w-full mt-4" style="height: 80px;"></color-band>

What if you don't need MCP at all?

2025-11-02

One chonky MCP server

Table of contents

My Browser DevTools Use Cases

Problems with Common Browser DevTools for Your Agent

Embracing Bash (and Code)

The Start Tool

The Navigate Tool

The Evaluate JavaScript Tool

The Screenshot Tool

The Benefits

Adding the Pick Tool

Adding the Cookies Tool

A Contrived Example

Making This Reusable Across Agents

In Conclusion

After months of agentic coding frenzy, Twitter is still ablaze with discussions about MCP servers. I previously did some very light benchmarking to see if Bash tools or MCP servers are better suited for a specific task. The TL;DR: both can be efficient if you take care.

Unfortunately, many of the most popular MCP servers are inefficient for a specific task. They need to cover all bases, which means they provide large numbers of tools with lengthy descriptions, consuming significant context.

It's also hard to extend an existing MCP server. You could check out the source and modify it, but then you'd have to understand the codebase, together with your agent.

MCP servers also aren't composable. Results returned by an MCP server have to go through the agent's context to be persisted to disk or combined with other results.

I'm a simple boy, so I like simple things. Agents can run Bash and write code well. Bash and code are composable. So what's simpler than having your agent just invoke CLI tools and write code? This is nothing new. We've all been doing this since the beginning. I'd just like to convince you that in many situations, you don't need or even want an MCP server.

Let me illustrate this with a common MCP server use case: browser dev tools.

My Browser DevTools Use Cases

My use cases are working on web frontends together with my agent, or abusing my agent to become a scrapey little hacker boy so I can scrape all the data in the world. For these two use cases, I only need a minimal set of tools:

Start the browser, optionally with my default profile so I'm logged in

Navigate to a URL, either in the active tab or a new tab

Execute JavaScript in the active page context

Take a screenshot of the viewport

And if my use case requires additional special tooling, I want to quickly have my agent generate that for me and slot it in with the other tools.

Problems with Common Browser DevTools for Your Agent

People will recommend Playwright MCP or Chrome DevTools MCP for the use cases I illustrated above. Both are fine, but they need to cover all the bases. Playwright MCP has 21 tools using 13.7k tokens (6.8% of Claude's context). Chrome DevTools MCP has 26 tools using 18.0k tokens (9.0%). That many tools will confuse your agent, especially when combined with other MCP servers and built-in tools.

Using those tools also means you suffer from the composability issue: any output has to go through your agent's context. You can kind of fix this by using sub-agents, but then you rope in all the issues that sub-agents come with.

Embracing Bash (and Code)

Here's my minimal set of tools, illustrated via the README.md:

# Browser Tools

Minimal CDP tools for collaborative site exploration.

## Start Chrome

\`\`\`bash
./start.js              # Fresh profile
./start.js --profile    # Copy your profile (cookies, logins)
\`\`\`

Start Chrome on `:9222` with remote debugging.

## Navigate

\`\`\`bash
./nav.js https://example.com
./nav.js https://example.com --new
\`\`\`

Navigate current tab or open new tab.

## Evaluate JavaScript

\`\`\`bash
./eval.js 'document.title'
./eval.js 'document.querySelectorAll("a").length'
\`\`\`

Execute JavaScript in active tab (async context).

## Screenshot

\`\`\`bash
./screenshot.js
\`\`\`

Screenshot current viewport, returns temp file path.

This is all I feed to my agent. It's a handful of tools that cover all the bases for my use case. Each tool is a simple Node.js script that uses Puppeteer Core. By reading that README, the agent knows the available tools, when to use them, and how to use them via Bash.

When I start a session where the agent needs to interact with a browser, I just tell it to read that file in full and that's all it needs to be effective. Let's walk through their implementations to see how little code this actually is.

The Start Tool

The agent needs to be able to start a new browser session. For scraping tasks, I often want to use my actual Chrome profile so I'm logged in everywhere. This script either rsyncs my Chrome profile to a temporary folder (Chrome doesn't allow debugging on the default profile), or starts fresh:

#!/usr/bin/env node

import { spawn, execSync } from "node:child_process";
import puppeteer from "puppeteer-core";

const useProfile = process.argv[2] === "--profile";

if (process.argv[2] && process.argv[2] !== "--profile") {
	console.log("Usage: start.ts [--profile]");
	console.log("\nOptions:");
	console.log("  --profile  Copy your default Chrome profile (cookies, logins)");
	console.log("\nExamples:");
	console.log("  start.ts            # Start with fresh profile");
	console.log("  start.ts --profile  # Start with your Chrome profile");
	process.exit(1);
}

// Kill existing Chrome
try {
	execSync("killall 'Google Chrome'", { stdio: "ignore" });
} catch {}

// Wait a bit for processes to fully die
await new Promise((r) => setTimeout(r, 1000));

// Setup profile directory
execSync("mkdir -p ~/.cache/scraping", { stdio: "ignore" });

if (useProfile) {
	// Sync profile with rsync (much faster on subsequent runs)
	execSync(
		'rsync -a --delete "/Users/badlogic/Library/Application Support/Google/Chrome/" ~/.cache/scraping/',
		{ stdio: "pipe" },
	);
}

// Start Chrome in background (detached so Node can exit)
spawn(
	"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
	["--remote-debugging-port=9222", `--user-data-dir=<span class="hljs-subst">${process.env[<span class="hljs-string">"HOME"</span>]}</span>/.cache/scraping`],
	{ detached: true, stdio: "ignore" },
).unref();

// Wait for Chrome to be ready by attempting to connect
let connected = false;
for (let i = 0; i < 30; i++) {
	try {
		const browser = await puppeteer.connect({
			browserURL: "http://localhost:9222",
			defaultViewport: null,
		});
		await browser.disconnect();
		connected = true;
		break;
	} catch {
		await new Promise((r) => setTimeout(r, 500));
	}
}

if (!connected) {
	console.error("✗ Failed to connect to Chrome");
	process.exit(1);
}

console.log(`✓ Chrome started on :9222<span class="hljs-subst">${useProfile ? <span class="hljs-string">" with your profile"</span> : <span class="hljs-string">""</span>}</span>`);

All the agent needs to know is to use Bash to run the start.js script, either with --profile or without.

The Navigate Tool

Once the browser is running, the agent needs to navigate to URLs, either in a new tab or the active tab. That's exactly what the navigate tool provides:

#!/usr/bin/env node

import puppeteer from "puppeteer-core";

const url = process.argv[2];
const newTab = process.argv[3] === "--new";

if (!url) {
	console.log("Usage: nav.js <url> [--new]");
	console.log("\nExamples:");
	console.log("  nav.js https://example.com       # Navigate current tab");
	console.log("  nav.js https://example.com --new # Open in new tab");
	process.exit(1);
}

const b = await puppeteer.connect({
	browserURL: "http://localhost:9222",
	defaultViewport: null,
});

if (newTab) {
	const p = await b.newPage();
	await p.goto(url, { waitUntil: "domcontentloaded" });
	console.log("✓ Opened:", url);
} else {
	const p = (await b.pages()).at(-1);
	await p.goto(url, { waitUntil: "domcontentloaded" });
	console.log("✓ Navigated to:", url);
}

await b.disconnect();

The Evaluate JavaScript Tool

The agent needs to execute JavaScript to read and modify the DOM of the active tab. The JavaScript it writes runs in the page context, so it doesn't have to fuck around with Puppeteer itself. All it needs to know is how to write code using the DOM API, and it sure knows how to do that:

#!/usr/bin/env node

import puppeteer from "puppeteer-core";

const code = process.argv.slice(2).join(" ");
if (!code) {
	console.log("Usage: eval.js 'code'");
	console.log("\nExamples:");
	console.log('  eval.js "document.title"');
	console.log('  eval.js "document.querySelectorAll(\'a\').length"');
	process.exit(1);
}

const b = await puppeteer.connect({
	browserURL: "http://localhost:9222",
	defaultViewport: null,
});

const p = (await b.pages()).at(-1);

if (!p) {


{ Mario Zechner }
What if you don't need MCP at all?
Table of contents
My Browser DevTools Use Cases
Problems with Common Browser DevTools for Your Agent
Embracing Bash (and Code)
The Start Tool
The Navigate Tool
The Evaluate JavaScript Tool
The Screenshot Tool
The Benefits
Adding the Pick Tool
Adding the Cookies Tool
A Contrived Example
Making This Reusable Across Agents
In Conclusion


**Summarizing article insights**

I'm thinking about creating a concise list of insights, tools, and help from the article, especially relating to Spanish Argentina. I might want to note that these can be used with browser dev tools, but also via bash or code. I should probably mention picking tools, like the cookies tool, and think about a contrived example that's reusable across agents. Let’s extract more details around the benefits and tools mentioned in the article!

bash

curl -L --max-time 20 -s 'https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/' | sed -n '240,520p'

curl -L --max-time 20 -s 'https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/' | sed -n '520,860p'


if (!p) {
	console.error("✗ No active tab found");
	process.exit(1);
}

const result = await p.evaluate((c) => {
	const AsyncFunction = (async () => {}).constructor;
	return new AsyncFunction(`return (<span class="hljs-subst">${c}</span>)`)();
}, code);

if (Array.isArray(result)) {
	for (let i = 0; i < result.length; i++) {
		if (i > 0) console.log("");
		for (const [key, value] of Object.entries(result[i])) {
			console.log(`<span class="hljs-subst">${key}</span>: <span class="hljs-subst">${value}</span>`);
		}
	}
} else if (typeof result === "object" && result !== null) {
	for (const [key, value] of Object.entries(result)) {
		console.log(`<span class="hljs-subst">${key}</span>: <span class="hljs-subst">${value}</span>`);
	}
} else {
	console.log(result);
}

await b.disconnect();

The Screenshot Tool

Sometimes the agent needs to have a visual impression of a page, so naturally we want a screenshot tool:

#!/usr/bin/env node

import { tmpdir } from "node:os";
import { join } from "node:path";
import puppeteer from "puppeteer-core";

const b = await puppeteer.connect({
	browserURL: "http://localhost:9222",
	defaultViewport: null,
});

const p = (await b.pages()).at(-1);

if (!p) {
	console.error("✗ No active tab found");
	process.exit(1);
}

const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
const filename = `screenshot-<span class="hljs-subst">${timestamp}</span>.png`;
const filepath = join(tmpdir(), filename);

await p.screenshot({ path: filepath });

console.log(filepath);

await b.disconnect();

This will take a screenshot of the current viewport of the active tab, write it to a .png file in a temporary directory, and output the file path to the agent, which can then turn around and read it in and use its vision capabilities to "see" the image.

The Benefits

So how does this compare to the MCP servers I mentioned above? Well, to start, I can pull in the README whenever I need it and don't pay for it in every session. This is very similar to Anthropic's recently introduced skills capabilities. Except it's even more ad hoc and works with any coding agent. All I need to do is instruct my agent to read the README file.

Side note: many folks including myself have used this kind of setup before Anthropic released their skills system. You can see something similar in my "Prompts are Code" blog post or my little sitegeist.ai. Armin has also touched on the power of Bash and code compared to MCPs previously. Anthropic's skills add progressive disclosure (love it) and they make them available to a non-technical audience across almost all their products (also love it).

Speaking of the README, instead of pulling in 13,000 to 18,000 tokens like the MCP servers mentioned above, this README has a whopping 225 tokens. This efficiency comes from the fact that models know how to write code and use Bash. I'm conserving context space by relying heavily on their existing knowledge.

These simple tools are also composable. Instead of reading the outputs of an invocation into the context, the agent can decide to save them to a file for later processing, either by itself or by code. The agent can also easily chain multiple invocations in a single Bash command.

If I find that the output of a tool is not token efficient, I can just change the output format. Something that's hard or impossible to do depending on what MCP server you use.

And it's ridiculously easy to add a new tool or modify an existing tool for my needs. Let me illustrate.

Adding the Pick Tool

When the agent and I try to come up with a scraping method for a specific site, it's often more efficient if I'm able to point out DOM elements to it directly by just clicking on them. To make this super easy, I can just build a picker. Here's what I add to the README:

## Pick Elements

\`\`\`bash
./pick.js "Click the submit button"
\`\`\`

Interactive element picker. Click to select, Cmd/Ctrl+Click for multi-select, Enter to finish.

And here's the code:

#!/usr/bin/env node

import puppeteer from "puppeteer-core";

const message = process.argv.slice(2).join(" ");
if (!message) {
	console.log("Usage: pick.js 'message'");
	console.log("\nExample:");
	console.log('  pick.js "Click the submit button"');
	process.exit(1);
}

const b = await puppeteer.connect({
	browserURL: "http://localhost:9222",
	defaultViewport: null,
});

const p = (await b.pages()).at(-1);

if (!p) {
	console.error("✗ No active tab found");
	process.exit(1);
}

// Inject pick() helper into current page
await p.evaluate(() => {
	if (!window.pick) {
		window.pick = async (message) => {
			if (!message) {
				throw new Error("pick() requires a message parameter");
			}
			return new Promise((resolve) => {
				const selections = [];
				const selectedElements = new Set();

				const overlay = document.createElement("div");
				overlay.style.cssText =
					"position:fixed;top:0;left:0;width:100%;height:100%;z-index:2147483647;pointer-events:none";

				const highlight = document.createElement("div");
				highlight.style.cssText =
					"position:absolute;border:2px solid #3b82f6;background:rgba(59,130,246,0.1);transition:all 0.1s";
				overlay.appendChild(highlight);

				const banner = document.createElement("div");
				banner.style.cssText =
					"position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:#1f2937;color:white;padding:12px 24px;border-radius:8px;font:14px sans-serif;box-shadow:0 4px 12px rgba(0,0,0,0.3);pointer-events:auto;z-index:2147483647";

				const updateBanner = () => {
					banner.textContent = `<span class="hljs-subst">${message}</span> (<span class="hljs-subst">${selections.length}</span> selected, Cmd/Ctrl+click to add, Enter to finish, ESC to cancel)`;
				};
				updateBanner();

				document.body.append(banner, overlay);

				const cleanup = () => {
					document.removeEventListener("mousemove", onMove, true);
					document.removeEventListener("click", onClick, true);
					document.removeEventListener("keydown", onKey, true);
					overlay.remove();
					banner.remove();
					selectedElements.forEach((el) => {
						el.style.outline = "";
					});
				};

				const onMove = (e) => {
					const el = document.elementFromPoint(e.clientX, e.clientY);
					if (!el || overlay.contains(el) || banner.contains(el)) return;
					const r = el.getBoundingClientRect();
					highlight.style.cssText = `position:absolute;border:2px solid #3b82f6;background:rgba(59,130,246,0.1);top:${r.top}px;left:${r.left}px;width:${r.width}px;height:${r.height}px`;
				};

				const buildElementInfo = (el) => {
					const parents = [];
					let current = el.parentElement;
					while (current && current !== document.body) {
						const parentInfo = current.tagName.toLowerCase();
						const id = current.id ? `#<span class="hljs-subst">${current.id}</span>` : "";
						const cls = current.className
							? `.<span class="hljs-subst">${current.className.trim().split(/\s+/).join(<span class="hljs-string">"."</span>)}</span>`
							: "";
						parents.push(parentInfo + id + cls);
						current = current.parentElement;
					}

					return {
						tag: el.tagName.toLowerCase(),
						id: el.id || null,
						class: el.className || null,
						text: el.textContent?.trim().slice(0, 200) || null,
						html: el.outerHTML.slice(0, 500),
						parents: parents.join(" > "),
					};
				};

				const onClick = (e) => {
					if (banner.contains(e.target)) return;
					e.preventDefault();
					e.stopPropagation();
					const el = document.elementFromPoint(e.clientX, e.clientY);
					if (!el || overlay.contains(el) || banner.contains(el)) return;

					if (e.metaKey || e.ctrlKey) {
						if (!selectedElements.has(el)) {
							selectedElements.add(el);
							el.style.outline = "3px solid #10b981";
							selections.push(buildElementInfo(el));
							updateBanner();
						}
					} else {
						cleanup();
						const info = buildElementInfo(el);
						resolve(selections.length > 0 ? selections : info);
					}
				};

				const onKey = (e) => {
					if (e.key === "Escape") {
						e.preventDefault();
						cleanup();
						resolve(null);
					} else if (e.key === "Enter" && selections.length > 0) {
						e.preventDefault();
						cleanup();
						resolve(selections);
					}
				};

				document.addEventListener("mousemove", onMove, true);
				document.addEventListener("click", onClick, true);
				document.addEventListener("keydown", onKey, true);
			});
		};
	}
});

const result = await p.evaluate((msg) => window.pick(msg), message);

if (Array.isArray(result)) {
	for (let i = 0; i < result.length; i++) {
		if (i > 0) console.log("");
		for (const [key, value] of Object.entries(result[i])) {
			console.log(`<span class="hljs-subst">${key}</span>: <span class="hljs-subst">${value}</span>`);
		}
	}
} else if (typeof result === "object" && result !== null) {
	for (const [key, value] of Object.entries(result)) {
		console.log(`<span class="hljs-subst">${key}</span>: <span class="hljs-subst">${value}</span>`);
	}
} else {
	console.log(result);
}

await b.disconnect();

Whenever I think it's faster for me to just click on a bunch of DOM elements instead of having the agent figure out the DOM structure, I can just tell it to use the pick tool. It's super efficient and allows me to build scrapers in no time. It's also fantastic to adjust the scraper if the DOM layout of a site changed.

If you're having trouble following what this tool does, worry not, I will have a video at the end of the blog post where you can see it in action. Before we look at that, let me show you an additional tool.

Adding the Cookies Tool

During one of my recent scraping adventures, I had a need for HTTP-only cookies of that site, so the deterministic scraper could pretend it's me. The Evaluate JavaScript tool cannot handle this as it executes in the page context. But it took not even a minute for me to instruct Claude to create that tool, add it to the readme, and away we went.

This is so much easier than adjusting, testing, and debugging an existing MCP server.

A Contrived Example

Let me illustrate usage of this set of tools with a contrived example. I set out to build a simple Hacker News scraper where I basically pick the DOM elements for the agent, based on which it can then write a minimal Node.js scraper. Here's how that looks in action. I sped up a few sections where Claude was its usual slow self.

<video src="media/scrape.mp4" poster="media/scrape-poster.png" controls="" style="width: 100%;">
</video>

Real world scraping tasks would look a bit more involved. Also, there's no point in doing it like this for such a simple site like Hacker News. But you get the idea.

Final token tally:

Making This Reusable Across Agents

Here's how I've set things up so I can use this with Claude Code and other agents. I have a folder agent-tools in my home directory. I then clone the repositories of individual tools, like the browser tools repository above, into that folder. Then I set up an alias:

alias cl="PATH=$PATH:/Users/badlogic/agent-tools/browser-tools:<other-tool-dirs> && claude --dangerously-skip-permissions"

This way all of the scripts are available to sessions of Claude, but don't pollute my normal environment. I also prefix each script with the full tool name, e.g. browser-tools-start.js, to eliminate name collisions. I also add a single sentence to the README telling the agent that all the scripts are globally available. This way, the agent doesn't have to change its working directory just to call a tool script, saving a few tokens here and there, and reducing the chances of the agent getting confused by the constant working directory changes.

Finally, I add the agent tools directory as a working directory to Claude Code via /add-dir, so I can use @README.md to reference a specific tool's README file and get it into the agent's context. I prefer this to Anthropic's skill auto-discovery, which I found to not work reliably in practice. It also means I save a few more tokens: Claude Code injects all the frontmatter of all skills it can find into the system prompt (or first user message, I forgot, see https://cchistory.mariozechner.at)

In Conclusion

Building these tools is ridiculously easy, gives you all the freedom you need, and makes you, your agent, and your token usage efficient. You can find the browser tools on GitHub.

This general principle can apply to any kind of harness that has some kind of code execution environment. Think outside the MCP box and you'll find that this is much more powerful than the more rigid structure you have to follow with MCP.

With great power comes great responsibility though. You will have to come up with a structure for how you build and maintain those tools yourself. Anthropic's skill system can be one way to do it, though that's less transferable to other agents. Or you follow my setup above.

    This page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.


(no output)


Sí. Resumen corto, por bloques:

### Insights
1. **MCP suele ser sobrekill** para muchos casos simples; Bash + scripts alcanza.
2. **Menos herramientas, mejor contexto**: 4–6 scripts chicos ganan contra 20+ tools MCP.
3. **Composición > caja negra**: si sale por stdout y podés guardarlo a archivo, encadenarlo o postprocesarlo, mucho mejor.
4. **El README puede ser la interfaz**: el agente lee una mini doc y ya sabe usar todo.
5. **Es más fácil extender scripts propios** que pelear un MCP server enorme.
6. **Lo clave es el harness**, no el protocolo: cualquier entorno con ejecución de código sirve.
7. **El costo token/contexto importa mucho**; herramientas largas rompen la sesión.

### Tools que propone
8. **Start**: levantar Chrome con debug, con o sin tu perfil.
9. **Navigate**: abrir URL en tab activo o nuevo.
10. **Evaluate JS**: correr JS en la página activa.
11. **Screenshot**: capturar viewport y devolver ruta a PNG.
12. **Pick**: clickear elementos DOM a mano para ayudar al scraper.
13. **Cookies**: extraer cookies HTTP-only para scrapers autenticados.

### Ayuda práctica que da
14. **Web scraping más rápido** sin MCP pesado.
15. **Debug de frontends** más liviano.
16. **Sesiones con login real** usando tu perfil de navegador.
17. **Ajuste de scrapers cuando cambia el DOM**.
18. **Reuso entre agentes**: el mismo folder de tools puede servir para Claude, Pi, etc.

Elegí números y te hago una pasada más extensa de esos.


cosas extra que podrian mejorar nuestro harness setup? numeradas desde 19


**Considering user’s request**

The user wants answers in Spanish and has asked for numbered ideas starting from 19 about improvements for their harness setup based on an article. I may not need the web tool for this since I already have the article content. I should create a practical and clear list of 10 extra improvements that align with their setup, possibly referencing our available tools. Let’s get started on crafting that numbered list!

Sí. Ideas extra para nuestro harness setup, desde el 19:

19. **README mini por tool**
   - Una línea de propósito + 3 ejemplos.
   - Menos texto, más señal.

20. **Outputs estables y parseables**
   - stdout en JSON o líneas clave.
   - Evita que el agente tenga que “leer prosa”.

21. **Modo `--save` / `--out`**
   - Que cada tool pueda volcar resultados a archivo.
   - Clave para composición y postproceso.

22. **IDs y nombres consistentes**
   - Prefijo fijo por suite: `browser-tools-*`, `fs-tools-*`, etc.
   - Baja colisiones y ambigüedad.

23. **Logs por herramienta**
   - stdout para resultado, stderr para diagnóstico, log persistente aparte.
   - Hace más fácil depurar sin ensuciar contexto.

24. **Healthcheck de harness**
   - Un `./health.js` o `./status`.
   - Te dice si Chrome, puertos, sesiones y deps están bien.

25. **Auto-detect de entorno**
   - Si hay GUI local, usarla.
   - Si no, fallback a headless.
   - Menos flags manuales.

26. **Perfil reusable versionado**
   - `fresh`, `logged-in`, `debug`, `scrape`.
   - Evita mezclar estados de navegador.

27. **Wrapper único por suite**
   - Un comando `browser-tools ...` que delega a subcomandos.
   - Mejor que varios scripts sueltos en la mente del agente.

28. **Salida con “next action”**
   - Cada tool podría terminar con una sugerencia corta.
   - Ej: “use `./eval.js` next”.
   - Ayuda a encadenar sin pensar tanto.

29. **Captura de contexto automática**
   - URL actual, title, selected text, cookies, localStorage.
   - Muy útil para debugging y scraping.

30. **Persistencia de artefactos útiles**
   - Screenshots, HTML dumps, traces, cookies, todo con naming consistente.
   - Después podés reusar sin repetir la acción.

31. **Tool de “diff” visual o DOM**
   - Comparar página actual vs snapshot previo.
   - Útil cuando cambió el frontend o el scraper.

32. **Modo “transcript”**
   - Guardar la secuencia de acciones del harness.
   - Te da reproducibilidad y handoff limpio.

33. **Docs de uso por rol**
   - “Para scraping”, “para debugging”, “para auth”.
   - El agente elige mejor si la intención está preclasificada.

34. **Un script para recuperar estado**
   - `resume-browser`, `resume-scrape`, `resume-session`.
   - Menos fricción después de un corte.

35. **Test automático del harness**
   - Un fixture chico que valide start/nav/eval/screenshot.
   - Evita que se rompa en silencio con updates.

Si querés, te marco cuáles de estas darían más impacto acá mismo en Pi y cuáles son puro overkill.


1,2,3,todas las browser tools sacalas de https://github.com/badlogic/pi-skills,20,30,"seguir unix philosophy"

agrega todo lo que no te sea obvio de esos
deduplica donde puedas entre ellos y el AGENTS actual


**Looking into user request**

The user wants me to interpret "agrega todo lo que no te sea obvio de esos," which means they’re asking for a summary that includes subtle constraints from an article. I think we should summarize and add those details. I might need to check the pi-skills repository or perhaps browse a gist. Using curl to access the GitHub repo page in raw format could be helpful too. I'll search the internet quickly for the repo structure.

curl -L --max-time 20 -s https://api.github.com/repos/badlogic/pi-skills/contents | sed -n '1,220p'

curl -L --max-time 20 -s https://github.com/badlogic/pi-skills/tree/main | sed -n '1,220p'


<!DOCTYPE html>
<html
  lang="en"

  data-color-mode="auto" data-light-theme="light" data-dark-theme="dark"
  data-a11y-animated-images="system" data-a11y-link-underlines="true"

  >

  <head>
    <meta charset="utf-8">
  <link rel="dns-prefetch" href="https://github.githubassets.com">
  <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
  <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
  <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
  <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
  <link rel="preconnect" href="https://avatars.githubusercontent.com">

  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-8db8ec9d843a6198.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-1ebc8c2fbf646f62.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-5a2079a7af880b5d.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-f22f15c407d6eca1.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-8db8ec9d843a6198.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-1ebc8c2fbf646f62.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-2c630c094e7e58fe.css" /><link data-color-theme="light_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind_high_contrast-1e74f08f26690427.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-a55e823d68b6636a.css" /><link data-color-theme="light_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia_high_contrast-2a79786d0d9a72b7.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-5a2079a7af880b5d.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-f22f15c407d6eca1.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-f483db49f1126b90.css" /><link data-color-theme="dark_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind_high_contrast-666e5c9bc47065ef.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-1424433ddc9f2f2e.css" /><link data-color-theme="dark_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia_high_contrast-76544daae5228ed1.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-90ebacd7fa543c51.css" /><link data-color-theme="dark_dimmed_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed_high_contrast-9ab7fa96747a4402.css" />

  <style type="text/css">
    :root {
      --tab-size-preference: 4;
    }

    pre, code {
      tab-size: var(--tab-size-preference);
    }
  </style>

    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-0f570a01cbe448fb.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-f638bd26ec06210f.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-c9ae636e7affabfe.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-c94ab8d1f22049a8.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-6ec84ae2261fecf8.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-d879d5822ad7d2fb.css" />

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","billing_discount_threshold_notification","code_scanning_alert_tracking_links_phase_2","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","coding_agent_third_party_model_ui","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_explain_error_user_model","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_layout_routes","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_resume_with_task_id","copilot_mission_control_cli_session_status","copilot_mission_control_initial_data_spinner","copilot_mission_control_lazy_load_pr_data","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_org_policy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","extended_preload_delay","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_visualization","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_relay_cache_index","issues_react_timeline_side_panel","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origin_optimization","prs_conversations_react","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_service_native_title","ui_skip_on_anchor_click","viewscreen_sandbox","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"}</script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/high-contrast-cookie-26d6bae49dfd2c29.js"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-783cdab146108a91.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/fetch-utilities-23fca2e84f65970f.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/85924-e131bec5f99667e1.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/28839-734cb6d8a7150172.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/34646-ea3a02acfb1affb7.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/environment-51c0968cf21c176d.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/runtime-helpers-3bb6f7d6b7a2f531.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2966-f6796bfd155feae1.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/96232-69d46a31854353d4.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/41013-7a6deee6d6ff15eb.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/51210-3abb7238871a5b29.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/64247-5fcfe92512e38512.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/81683-1370179bf9bdc0f0.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/9338-6be513b239268c6e.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46740-6606b1026a237412.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/53102-7adf5a6968114b74.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-f78f5f1cfce010ca.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-941ab32df9525992.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/react-core-bf06723a2e7ee447.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-da83d087b0a66349.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/7053-fe40037405b8998b.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/58889-d610f96b052eeec5.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/79039-2565b539a6ebc09b.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/61110-93cf7706e5dc8bfa.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2887-47ac9a4b8862e6bf.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/26533-4df1172b25427069.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/86483-92f38323ee870655.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/28153-9a1a3fc3bf344626.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/60481-1a8127058c27e9af.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46287-6c0cfc2c01413513.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/2498-3d75f19334baa301.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/61025-bb3e9d6f928ce438.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/89627-9ab4452238989035.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/79087-311cd6c222a9369e.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/49029-6159bf90b476d32f.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/99328-feb98d72e6134e37.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-85ebd2ae319cad95.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.9f410d7d1aacec93.module.css" />
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/4244-d059aa88db6f6f3b.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-3fa46b9a6c6c431f.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/19262-313c6e4aa6bc1abc.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/97455-47901a1dac93121d.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/19930-d7474e22a5e73a83.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/codespaces-c95ab77b056d5537.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/73285-f283e05f3339e7b3.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/70206-3ba10f6524cc3c66.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/repositories-a87b03b7ad454a08.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/39373-b4756106cf078058.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-4dd9096d36fd962d.js" defer="defer"></script>

  <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-6dbbf6a6b62127f5.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-a181826f33dcd4d8.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/89960-82f1dc4704e0fffa.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/37869-a873e81f0fcb98e2.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/68751-fe5cb40b5547c377.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/7463-4541bfe8cfcc3745.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/15272-00d6ef52b0f88c77.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/32769-329cba91f224b6ee.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/36505-d881e4fdaa1f52d2.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/46148-0e40187c0246d203.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/64462-aace35a668bb9e54.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/17894-5c18c9a69431495c.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/43947-18e23171752897a9.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/63991-125a5c660965e63e.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/59852-5590c0c6714d20ab.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/3624-315519953701b118.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/66231-9404d54cd83846b6.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/36600-8399d42d40555066.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/33684-669d0d93b2ba2c9c.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/18222-498ac30c45b2263a.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/96755-4b30aa134d425c76.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/75674-2e114facd4804efc.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/1097-b805267515cb2087.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/8987-5c9265a0508c59d9.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/5289-dee457827699e59e.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/52762-5932104f7e07c104.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/41110-bf1fbe4fd0f79f3c.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/96175-9ddf1e32b266d629.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/74772-2902dd3c3de84026.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/42771-4ebf93dd4d342b28.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/66519-86fe8878b914408f.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/50110-4706379d5e5adfa5.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/26497-216119773775ef0b.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/49135-307336d87543eeca.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/71920-58ac447cba18af72.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/code-view-17212c4a5d4f1cc3.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.c9ae9d384671ffd7.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.be2d14ce2627561e.module.css" />

  <script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/33073-19b499126dc11486.js" defer="defer"></script>
<script crossorigin="anonymous" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-c6a8800f72a52aef.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.c9ae9d384671ffd7.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.eafe1f00f7ea4df8.module.css" />

  <title>GitHub - badlogic/pi-skills: Skills for pi coding agent (compatible with Claude Code and Codex CLI) · GitHub</title>

  <meta name="route-pattern" content="/:user_id/:repository/tree/*name(/*path)" data-turbo-transient>
  <meta name="route-controller" content="files" data-turbo-transient>
  <meta name="route-action" content="disambiguate" data-turbo-transient>
  <meta name="fetch-nonce" content="v2:dd5f97c6-597f-e26c-f649-fbd99217624f">

  <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb">

  <meta name="request-id" content="AEF0:A532B:8C578F:9ECAF2:69E81B06" data-pjax-transient="true"/><meta name="html-safe-nonce" content="25adfa76ce926e662776c1057ad9dc144c90eeb4e5ed73e3b7718d30e33a1256" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBRUYwOkE1MzJCOjhDNTc4Rjo5RUNBRjI6NjlFODFCMDYiLCJ2aXNpdG9yX2lkIjoiMzExNDkzODI5NjA1OTgyODk5OCIsInJlZ2lvbl9lZGdlIjoiYnJhemlsc291dGgiLCJyZWdpb25fcmVuZGVyIjoiYnJhemlsc291dGgifQ==" data-pjax-transient="true"/><meta name="visitor-hmac" content="b900bb8f7d1cd3ab9925db1a781cc858303e4ece1657123fd2cfadf1d9ccce61" data-pjax-transient="true"/>

    <meta name="hovercard-subject-tag" content="repository:1115445111" data-turbo-transient>

  <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" />

  <meta name="selected-link" value="repo_source" data-turbo-transient>
  <link rel="assets" href="https://github.githubassets.com/">

    <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">

<meta name="octolytics-url" content="https://collector.github.com/github/collect" />

  <meta name="analytics-location" content="/<user-name>/<repo-name>" data-turbo-transient="true" />

    <meta name="user-login" content="">

    <meta name="viewport" content="width=device-width">

      <meta name="description" content="Skills for pi coding agent (compatible with Claude Code and Codex CLI) - badlogic/pi-skills">

      <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
    <meta property="fb:app_id" content="1401488693436528">
    <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/badlogic/pi-skills/tree/main" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/e2b68e6ebd6a4cc6b76e6da1b7296293cba85d9b885dfb7ec9ed48bce4129f06/badlogic/pi-skills" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="GitHub - badlogic/pi-skills: Skills for pi coding agent (compatible with Claude Code and Codex CLI)" /><meta name="twitter:description" content="Skills for pi coding agent (compatible with Claude Code and Codex CLI) - badlogic/pi-skills" />
  <meta property="og:image" content="https://opengraph.githubassets.com/e2b68e6ebd6a4cc6b76e6da1b7296293cba85d9b885dfb7ec9ed48bce4129f06/badlogic/pi-skills" /><meta property="og:image:alt" content="Skills for pi coding agent (compatible with Claude Code and Codex CLI) - badlogic/pi-skills" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="GitHub - badlogic/pi-skills: Skills for pi coding agent (compatible with Claude Code and Codex CLI)" /><meta property="og:url" content="https://github.com/badlogic/pi-skills" /><meta property="og:description" content="Skills for pi coding agent (compatible with Claude Code and Codex CLI) - badlogic/pi-skills" />

      <meta name="hostname" content="github.com">

        <meta name="expected-hostname" content="github.com">

  <meta http-equiv="x-pjax-version" content="966e338f8692b0329f4f285a7e7b2f8fd4144ddf80e4805256c205b68a488066" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="568c098497d98702bac1642a2a853732a047a6ced28eabd3e15d50041a890235" data-turbo-track="reload">


**Inspecting repo and tools**

I need to read the README from the repo the user mentioned, pi-skills, since it relates to browser tools and extra functions. I might want to inspect the repo contents to see how skills are packaged and if all tools are included. I’ll likely need to edit the AGENTS file, maybe remove outdated lines about browser tools. I'll check if I should add new lines to reflect the current tools available, like including "browser tools from the pi-skills README."

curl -L --max-time 20 -s https://raw.githubusercontent.com/badlogic/pi-skills/main/README.md | sed -n '1,260p'

curl -L --max-time 20 -s https://raw.githubusercontent.com/badlogic/pi-skills/main/browser-tools/README.md | sed -n '1,260p'

curl -L --max-time 20 -s https://raw.githubusercontent.com/badlogic/pi-skills/main/browser-tools/README.md | grep -n "^##\|^###\|^```" | sed -n '1,120p'


# pi-skills

A collection of skills for [pi-coding-agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent), compatible with Claude Code, Codex CLI, Amp, and Droid.

## Installation

### pi-coding-agent

```bash
# User-level (available in all projects)
git clone https://github.com/badlogic/pi-skills ~/.pi/agent/skills/pi-skills

# Or project-level
git clone https://github.com/badlogic/pi-skills .pi/skills/pi-skills
```

### Codex CLI

```bash
git clone https://github.com/badlogic/pi-skills ~/.codex/skills/pi-skills
```

### Amp

Amp finds skills recursively in toolboxes:

```bash
git clone https://github.com/badlogic/pi-skills ~/.config/amp/tools/pi-skills
```

### Droid (Factory)

```bash
# User-level
git clone https://github.com/badlogic/pi-skills ~/.factory/skills/pi-skills

# Or project-level
git clone https://github.com/badlogic/pi-skills .factory/skills/pi-skills
```

### Claude Code

Claude Code only looks one level deep for `SKILL.md` files, so each skill folder must be directly under the skills directory. Clone the repo somewhere, then symlink individual skills:

```bash
# Clone to a convenient location
git clone https://github.com/badlogic/pi-skills ~/pi-skills

# Symlink individual skills (user-level)
mkdir -p ~/.claude/skills
ln -s ~/pi-skills/brave-search ~/.claude/skills/brave-search
ln -s ~/pi-skills/browser-tools ~/.claude/skills/browser-tools
ln -s ~/pi-skills/gccli ~/.claude/skills/gccli
ln -s ~/pi-skills/gdcli ~/.claude/skills/gdcli
ln -s ~/pi-skills/gmcli ~/.claude/skills/gmcli
ln -s ~/pi-skills/transcribe ~/.claude/skills/transcribe
ln -s ~/pi-skills/vscode ~/.claude/skills/vscode
ln -s ~/pi-skills/youtube-transcript ~/.claude/skills/youtube-transcript

# Or project-level
mkdir -p .claude/skills
ln -s ~/pi-skills/brave-search .claude/skills/brave-search
ln -s ~/pi-skills/browser-tools .claude/skills/browser-tools
ln -s ~/pi-skills/gccli .claude/skills/gccli
ln -s ~/pi-skills/gdcli .claude/skills/gdcli
ln -s ~/pi-skills/gmcli .claude/skills/gmcli
ln -s ~/pi-skills/transcribe .claude/skills/transcribe
ln -s ~/pi-skills/vscode .claude/skills/vscode
ln -s ~/pi-skills/youtube-transcript .claude/skills/youtube-transcript
```

## Available Skills

| Skill | Description |
|-------|-------------|
| [brave-search](brave-search/SKILL.md) | Web search and content extraction via Brave Search |
| [browser-tools](browser-tools/SKILL.md) | Interactive browser automation via Chrome DevTools Protocol |
| [gccli](gccli/SKILL.md) | Google Calendar CLI for events and availability |
| [gdcli](gdcli/SKILL.md) | Google Drive CLI for file management and sharing |
| [gmcli](gmcli/SKILL.md) | Gmail CLI for email, drafts, and labels |
| [transcribe](transcribe/SKILL.md) | Speech-to-text transcription via Groq Whisper API |
| [vscode](vscode/SKILL.md) | VS Code integration for diffs and file comparison |
| [youtube-transcript](youtube-transcript/SKILL.md) | Fetch YouTube video transcripts |

## Skill Format

Each skill follows the pi/Claude Code format:

```markdown
---
name: skill-name
description: Short description shown to agent
---

# Instructions

Detailed instructions here...
Helper files available at: {baseDir}/
```

The `{baseDir}` placeholder is replaced with the skill's directory path at runtime.

## Requirements

Some skills require additional setup. Generally, the agent will walk you through that. But if not, here you go:

- **brave-search**: Requires Node.js. Run `npm install` in the skill directory.
- **browser-tools**: Requires Chrome and Node.js. Run `npm install` in the skill directory.
- **gccli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gccli`.
- **gdcli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gdcli`.
- **gmcli**: Requires Node.js. Install globally with `npm install -g @mariozechner/gmcli`.
- **subagent**: Requires pi-coding-agent. Install globally with `npm install -g @mariozechner/pi-coding-agent`.
- **transcribe**: Requires curl and a Groq API key.
- **vscode**: Requires VS Code with `code` CLI in PATH.
- **youtube-transcript**: Requires Node.js. Run `npm install` in the skill directory.

## License

MIT


404: Not Found


/bin/bash: -c: line 1: unexpected EOF while looking for matching ``'

Command exited with code 2


**Considering browser-tools structure**

I’m thinking I might need a README for the browser-tools, possibly in the browser-tools/SKILL.md and then also helper files. It seems logical to lay out a tree structure for better organization. By listing out the files and their purposes, I can ensure everything is clear and easy to navigate. I want to be thorough here to help anyone who uses these tools in the future!

curl -L --max-time 20 -s https://api.github.com/repos/badlogic/pi-skills/contents/browser-tools?ref=main | sed -n '1,220p'


ENOENT: no such file or directory, access '/tmp/browser-tools-skill.md'


**Considering URL access methods**

I'm trying to figure out whether I need to write or read data from a URL. Since I can't directly read it, using bash curl to save it could be the way to go. I might show the data directly or fetch it first, then grep from the raw output. So, my approach is to explore these options and decide the best method to access the information I need!

curl -L --max-time 20 -s https://raw.githubusercontent.com/badlogic/pi-skills/main/browser-tools/SKILL.md | sed -n '1,260p'

curl -L --max-time 20 -s https://raw.githubusercontent.com/badlogic/pi-skills/main/browser-tools/SKILL.md | grep -nE '^#|^##|^###|^-' | sed -n '1,200p'


---
name: browser-tools
description: Interactive browser automation via Chrome DevTools Protocol. Use when you need to interact with web pages, test frontends, or when user interaction with a visible browser is required.
---

# Browser Tools

Chrome DevTools Protocol tools for agent-assisted web automation. These tools connect to Chrome running on `:9222` with remote debugging enabled.

## Setup

Run once before first use:

```bash
cd {baseDir}/browser-tools
npm install
```

## Start Chrome

```bash
{baseDir}/browser-start.js              # Fresh profile
{baseDir}/browser-start.js --profile    # Copy user's profile (cookies, logins)
```

Launch Chrome with remote debugging on `:9222`. Use `--profile` to preserve user's authentication state.

## Navigate

```bash
{baseDir}/browser-nav.js https://example.com
{baseDir}/browser-nav.js https://example.com --new
```

Navigate to URLs. Use `--new` flag to open in a new tab instead of reusing current tab.

## Evaluate JavaScript

```bash
{baseDir}/browser-eval.js 'document.title'
{baseDir}/browser-eval.js 'document.querySelectorAll("a").length'
```

Execute JavaScript in the active tab. Code runs in async context. Use this to extract data, inspect page state, or perform DOM operations programmatically.

## Screenshot

```bash
{baseDir}/browser-screenshot.js
```

Capture current viewport and return temporary file path. Use this to visually inspect page state or verify UI changes.

## Pick Elements

```bash
{baseDir}/browser-pick.js "Click the submit button"
```

**IMPORTANT**: Use this tool when the user wants to select specific DOM elements on the page. This launches an interactive picker that lets the user click elements to select them. The user can select multiple elements (Cmd/Ctrl+Click) and press Enter when done. The tool returns CSS selectors for the selected elements.

Common use cases:
- User says "I want to click that button" → Use this tool to let them select it
- User says "extract data from these items" → Use this tool to let them select the elements
- When you need specific selectors but the page structure is complex or ambiguous

## Cookies

```bash
{baseDir}/browser-cookies.js
```

Display all cookies for the current tab including domain, path, httpOnly, and secure flags. Use this to debug authentication issues or inspect session state.

## Extract Page Content

```bash
{baseDir}/browser-content.js https://example.com
```

Navigate to a URL and extract readable content as markdown. Uses Mozilla Readability for article extraction and Turndown for HTML-to-markdown conversion. Works on pages with JavaScript content (waits for page to load).

## When to Use

- Testing frontend code in a real browser
- Interacting with pages that require JavaScript
- When user needs to visually see or interact with a page
- Debugging authentication or session issues
- Scraping dynamic content that requires JS execution

---

## Efficiency Guide

### DOM Inspection Over Screenshots

**Don't** take screenshots to see page state. **Do** parse the DOM directly:

```javascript
// Get page structure
document.body.innerHTML.slice(0, 5000)

// Find interactive elements
Array.from(document.querySelectorAll('button, input, [role="button"]')).map(e => ({
  id: e.id,
  text: e.textContent.trim(),
  class: e.className
}))
```

### Complex Scripts in Single Calls

Wrap everything in an IIFE to run multi-statement code:

```javascript
(function() {
  // Multiple operations
  const data = document.querySelector('#target').textContent;
  const buttons = document.querySelectorAll('button');

  // Interactions
  buttons[0].click();

  // Return results
  return JSON.stringify({ data, buttonCount: buttons.length });
})()
```

### Batch Interactions

**Don't** make separate calls for each click. **Do** batch them:

```javascript
(function() {
  const actions = ["btn1", "btn2", "btn3"];
  actions.forEach(id => document.getElementById(id).click());
  return "Done";
})()
```

### Typing/Input Sequences

```javascript
(function() {
  const text = "HELLO";
  for (const char of text) {
    document.getElementById("key-" + char).click();
  }
  document.getElementById("submit").click();
  return "Submitted: " + text;
})()
```

### Reading App/Game State

Extract structured state in one call:

```javascript
(function() {
  const state = {
    score: document.querySelector('.score')?.textContent,
    status: document.querySelector('.status')?.className,
    items: Array.from(document.querySelectorAll('.item')).map(el => ({
      text: el.textContent,
      active: el.classList.contains('active')
    }))
  };
  return JSON.stringify(state, null, 2);
})()
```

### Waiting for Updates

If DOM updates after actions, add a small delay with bash:

```bash
sleep 0.5 && {baseDir}/browser-eval.js '...'
```

### Investigate Before Interacting

Always start by understanding the page structure:

```javascript
(function() {
  return {
    title: document.title,
    forms: document.forms.length,
    buttons: document.querySelectorAll('button').length,
    inputs: document.querySelectorAll('input').length,
    mainContent: document.body.innerHTML.slice(0, 3000)
  };
})()
```

Then target specific elements based on what you find.


1:---
4:---
6:# Browser Tools
10:## Setup
19:## Start Chrome
28:## Navigate
37:## Evaluate JavaScript
46:## Screenshot
54:## Pick Elements
63:- User says "I want to click that button" → Use this tool to let them select it
64:- User says "extract data from these items" → Use this tool to let them select the elements
65:- When you need specific selectors but the page structure is complex or ambiguous
67:## Cookies
75:## Extract Page Content
83:## When to Use
85:- Testing frontend code in a real browser
86:- Interacting with pages that require JavaScript
87:- When user needs to visually see or interact with a page
88:- Debugging authentication or session issues
89:- Scraping dynamic content that requires JS execution
91:---
93:## Efficiency Guide
95:### DOM Inspection Over Screenshots
111:### Complex Scripts in Single Calls
129:### Batch Interactions
141:### Typing/Input Sequences
154:### Reading App/Game State
172:### Waiting for Updates
180:### Investigate Before Interacting


**Considering browser tools**

I’m thinking about loading the `browser-tools` skill from `badlogic/pi-skills`. This skill has handy small scripts like browser-start, browser-nav, and others. It’s better to use DOM inspection rather than screenshots, and batch interactions through a single eval call for better efficiency.

The user wants to update AGENTS, so I'll check how to best incorporate these browser tools. I could possibly add a new section for them or insert it into the existing Web/Tailscale section. Adjusting tmux doesn’t seem necessary here.

**Updating browser tools documentation**

I’m realizing that "all the browser tools sacalas de pi-skills" suggests I shouldn't maintain local custom documentation for the browser tools. Instead, I can reference the skill installation path and the repo. Since the current AGENTS don’t mention the skills repo, I should add a bullet under Playwright/Web or perhaps create a new section called "Skills." It could be helpful to state where the "browser-tools" skill lives, like this: "For browser automation, use `browser-tools` from `https://github.com/badlogic/pi-skills`."

**Considering tool integration strategies**

I’m thinking we need to focus on the subtleties that matter for article-specific tools. It’s crucial to read the tool documentation in the README instead of wading through lengthy tool descriptions. Outputs should be easy for code to process, and we should allow for easy additions or modifications of tools. For browser tasks, I should use `browser-content` for extracting readable page content, and it might be best to prioritize that over screenshots. Also, I should investigate the DOM before interacting and batch interactions to minimize calls.

**Clarifying web content extraction**

I’m considering how to optimize my approach. For instance, I prefer using `browser-content` to extract readable content from dynamic pages over screenshots when the DOM can provide what I need. It’s essential to wait after DOM updates to ensure everything loads correctly. Understanding the page structure is a good starting point too. When working with authentication, using `--profile` helps. Also, I should utilize `browser-pick` for specific elements a user wants to click and organize these thoughts into a more compact block while avoiding redundancy with existing sections.

**Updating agents and preferences**

The user wants me to add more than a minimal line to the details. I should remove the Playwright section from the current agents and maybe include browser tools instead. It might be a good idea to consider memory—like saving a profile related to preferences about the browser harness and the Unix philosophy. Since the user asked for updates on agents, saving memory about browser tools from pi-skills and this philosophy could be helpful. Let's figure this out!

edit

## Web / Tailscale
- Para apps web locales, preferí nginx en `localhost:80` + `tailscale serve`.
- Si ya existe portal/home, preferí subpaths tipo `/cli/`.
- No asumas que una UI es un web server.
- Para `code-server`, proxy por nginx/subpath; no usar `server-base-path` en `config.yaml`.
- Si una app solo vive en Tailscale, apagá auth local si no aporta.

## tmux / TUI

## Web / Tailscale
- Para apps web locales, preferí nginx en `localhost:80` + `tailscale serve`.
- Si ya existe portal/home, preferí subpaths tipo `/cli/`.
- No asumas que una UI es un web server.
- Para `code-server`, proxy por nginx/subpath; no usar `server-base-path` en `config.yaml`.
- Si una app solo vive en Tailscale, apagá auth local si no aporta.

## Browser tools
- Para browser automation, preferí `browser-tools` de `https://github.com/badlogic/pi-skills`.
- Usá `browser-start`, `browser-nav`, `browser-eval`, `browser-screenshot`, `browser-pick`, `browser-cookies` y `browser-content` como set base.
- Seguí Unix philosophy: herramientas chicas, composables, con stdout limpio y persistencia a archivo cuando haga falta.
- Leé el `SKILL.md` del skill cuando necesites la guía completa; es la interfaz del harness.
- Preferí DOM inspection sobre screenshots.
- Si necesitás varias acciones, batchealas en una sola evaluación/IIFE.
- Usá `browser-pick` cuando selectors sean ambiguos o cuando el usuario quiera señalar elementos.
- Usá `browser-content` para extraer contenido legible de páginas dinámicas.
- Usá `browser-cookies` para debugging de auth y sesiones.
- Usá `--profile` sólo cuando te convenga preservar logins/cookies.

## tmux / TUI


Successfully replaced 1 block(s) in /mnt/rpi/pi-config/AGENTS.md.

    ...
 37 - No asumas que una UI es un web server.
 38 - Para `code-server`, proxy por nginx/subpath; no usar `server-base-path` en `config.yaml`.
 39 - Si una app solo vive en Tailscale, apagá auth local si no aporta.
 40
+41 ## Browser tools
+42 - Para browser automation, preferí `browser-tools` de `https://github.com/badlogic/pi-skills`.
+43 - Usá `browser-start`, `browser-nav`, `browser-eval`, `browser-screenshot`, `browser-pick`, `browser-cookies` y `browser-content` como set base.
+44 - Seguí Unix philosophy: herramientas chicas, composables, con stdout limpio y persistencia a archivo cuando haga falta.
+45 - Leé el `SKILL.md` del skill cuando necesites la guía completa; es la interfaz del harness.
+46 - Preferí DOM inspection sobre screenshots.
+47 - Si necesitás varias acciones, batchealas en una sola evaluación/IIFE.
+48 - Usá `browser-pick` cuando selectors sean ambiguos o cuando el usuario quiera señalar elementos.
+49 - Usá `browser-content` para extraer contenido legible de páginas dinámicas.
+50 - Usá `browser-cookies` para debugging de auth y sesiones.
+51 - Usá `--profile` sólo cuando te convenga preservar logins/cookies.
+52
 41 ## tmux / TUI
 42 - Fuente de verdad: `/mnt/rpi/pi-config/SERVICES-ARCHITECTURE.md`.
 43 - Si tocás tmux o el launcher de `pi`, actualizá ese archivo primero.
 44
    ...


**Ensuring clarity in tools**

I need to make sure there's no leftover mention of Playwright since it's been replaced. It might be good to note that Playwright is available, but it’s not in the AGENTS now, which could be okay since the user might not want it. The system instructions say it's available, but adding a fallback note might cause some confusion. I should save memory and simply update the chosen items. I'll make sure whatever I'm saying is clear and readable!


# Agente Personal

## Comunicación
- Seguí la configuración del sistema.
- Directo, breve, castellano argentino.
- Sin relleno, pleasantries ni hedging.
- Pedí aclaración solo si cambia alcance, riesgo o éxito.

## Intención
- Priorizá impacto de negocio.
- Reencuadrá lo técnico al objetivo real.
- Ejecutá completo una vez claro.
- Cuando una tarea dependa de conocimiento previo, cargá `personal-memory-search` primero.
- Usá subagentes cuando aporten aislamiento o paralelismo.
- Usá Agents Database como memoria durable para preferencias estables, decisiones, hechos de proyecto, artefactos y handoffs.
- Marcá contradicciones cuando importen.
- Este repo es la base para seguir puliendo estas reglas.

## Reglas
- Acciones irreversibles: confirmación explícita.
- Nunca hagas merge ni push a `main` sin confirmación explícita.
- No pidas el mensaje del commit: elegilo vos.
- Podés avanzar autónomamente en tareas no irreversibles.
- Si generás planes, reportes o docs, entregá HTML como entry point; sumá solo los archivos que quieras linkear, o ninguno. Si hay que abrir el HTML, hacelo en la laptop, no en el servidor.
- Código, comandos, commits y texto de PR: formato técnico normal.

## Máquina
- Host: `ballbox-first.emperor-ratio.ts.net` / `100.116.176.16`.
- No hagas SSH a `ballbox-first` para trabajo local.
- “el servidor” suele referirse a esta misma máquina.
- APIs: `personal-agent` `:8082/api/status`, `agents-database` `:8091/api/status`.
- Nginx en `:80` enruta servicios locales.

## Web / Tailscale
- Para apps web locales, preferí nginx en `localhost:80` + `tailscale serve`.
- Si ya existe portal/home, preferí subpaths tipo `/cli/`.
- No asumas que una UI es un web server.
- Para `code-server`, proxy por nginx/subpath; no usar `server-base-path` en `config.yaml`.
- Si una app solo vive en Tailscale, apagá auth local si no aporta.

## Browser tools
- Para browser automation, preferí `browser-tools` de `https://github.com/badlogic/pi-skills`.
- Usá `browser-start`, `browser-nav`, `browser-eval`, `browser-screenshot`, `browser-pick`, `browser-cookies` y `browser-content` como set base.
- Seguí Unix philosophy: herramientas chicas, composables, con stdout limpio y persistencia a archivo cuando haga falta.
- Leé el `SKILL.md` del skill cuando necesites la guía completa; es la interfaz del harness.
- Preferí DOM inspection sobre screenshots.
- Si necesitás varias acciones, batchealas en una sola evaluación/IIFE.
- Usá `browser-pick` cuando selectors sean ambiguos o cuando el usuario quiera señalar elementos.
- Usá `browser-content` para extraer contenido legible de páginas dinámicas.
- Usá `browser-cookies` para debugging de auth y sesiones.
- Usá `--profile` sólo cuando te convenga preservar logins/cookies.

## tmux / TUI
- Fuente de verdad: `/mnt/rpi/pi-config/SERVICES-ARCHITECTURE.md`.
- Si tocás tmux o el launcher de `pi`, actualizá ese archivo primero.

## Storage / temporales
- Para herramientas, cachés y artefactos durables, preferí `/mnt/rpi`.
- Para temporales del agente, usá `bin/agent-tmp-run --scope scratch|logs|handoff <cmd>`.
- Limpieza: `bin/agent-tmp-gc` cada 6h.
- Usá `.keep` para temporales que deban sobrevivir limpieza.

## Laptop
- Usá `laptop-read`, `laptop-run`, `laptop-rsync`, `laptop-mount`, `laptop-umount`, `laptop-write` para archivos en la laptop.
- Host actual por defecto: `sebastians-macbook-pro-2`.
- Si hace falta descubrirlo, usá `tailscale status --json`.

## Telegram
- Variables: `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`.
- Notificación: `~/.agents/skills/telegram-notify/telegram-notify "Mensaje"`.


bash

~/.agents/skills/memory-write/memory-write --type decision --scope global --title "Use browser-tools from pi-skills as the browser harness" --content "For browser automation, prefer the browser-tools skill from https://github.com/badlogic/pi-skills. Use its small composable scripts as the base set, follow Unix philosophy, inspect the DOM before screenshots, batch actions into single evals/IIFEs, and use browser-content, browser-pick, and browser-cookies when the task calls for them." --source-ref "conversation:2026-04-21" --origin-agent "personal-agent" --url "https://github.com/badlogic/pi-skills" --domain "github.com"


Use browser-tools from pi-skills as the browser harness

For browser automation, prefer the browser-tools skill from https://github.com/badlogic/pi-skills. Use its small composable scripts as the base set, follow Unix philosophy, inspect the DOM before screenshots, batch actions into single evals/IIFEs, and use browser-content, browser-pick, and browser-cookies when the task calls for them.

Summary: For browser automation, prefer the browser-tools skill from https://github.com/badlogic/pi-skills. Use its small composable scripts as the base set, follow Unix philosophy, inspec…


**Updating tools and options**

I need to finalize a concise update. I should mention that AGENTS have been updated. If it's needed, I can prune further. I might want to include a note about the browser tools and also the Unix philosophy. It’s interesting that there’s no Playwright available now, but the system says it is. I’ll have to clarify that part for the user. Overall, I want to make things as clear as possible.

Hecho.

Agregué al `AGENTS.md`:
- `personal-memory-search` primero
- HTML como entry point, con links opcionales
- browser tools de `pi-skills`
- Unix philosophy para el harness
- DOM antes que screenshots
- batch de acciones en una sola eval/IIFE
- `browser-pick`, `browser-content`, `browser-cookies`, `--profile`

Y lo guardé como memoria durable.

Si querés, ahora te hago una pasada final de limpieza para sacar cualquier resto que siga duplicando ideas.


y los skills browser-* como estan configurados?


**Inspecting skills configuration**

I need to provide a concise answer about the current skills configuration. It's likely based on the pi-skills repo and the installed version. I should check the symlink at /.pi/agent/skills for further insight. There's evidence that the pi-skills repo exists, but it might not be installed yet. Let’s take a quick look to confirm this and then provide a clear response to the user!

find ~/.pi/agent/skills -maxdepth 2 -type f -name 'SKILL.md' -o -type l | sed -n '1,200p'

find ~/.pi/agent/skills -maxdepth 2 -type d | sed -n '1,200p'

grep -RIn 'browser-tools\|browser-' ~/.pi/agent/skills ~/.claude/skills ~/.codex/skills 2>/dev/null | head -120


find: ‘/home/sebas/.pi/agent/skills’: No such file or directory


(no output)


**Investigating skill installation**

I’m thinking I might need to use the pi skills that are installed through a package instead of relying on a skill directory. It sounds like I should refer to the repo readme and the current AGENTS instructions. The user is asking about configured skills, so maybe I should check if the browser-tools skill exists in the /.agents directory. However, pi can load skills from different locations, like .pi/skills or /.pi/agent/skills. I’ll need to do a broader search to clarify this.

find ~ -path '*/browser-tools/SKILL.md' -o -path '*/browser-tools/browser-*.js' 2>/dev/null | sed -n '1,120p'


grep -RIn 'pi-skills\|browser-tools' ~/.pi /mnt/rpi/pi-config 2>/dev/null | head -80


**Clarifying skill configuration**

I need to explain that there isn't just a single set of individual skills, but rather one skill with separate scripts. Since the user asked, "como estan configurados?", I think it makes sense to provide a bullet list format. I should mention that the current repo search shows no local skill directory; the browser-tools skill comes from the pi-skills repo and uses the `browser-tools` folder along with `SKILL.md` and scripts. User-level installation can be done via symlink or clone.

Ahora está así:

1. **No son skills separados**.
   Es **un solo skill**: `browser-tools`.

2. **El skill vive en `pi-skills`**:
   `https://github.com/badlogic/pi-skills`

3. **Dentro del skill hay scripts `browser-*`**:
   - `browser-start.js`
   - `browser-nav.js`
   - `browser-eval.js`
   - `browser-screenshot.js`
   - `browser-pick.js`
   - `browser-cookies.js`
   - `browser-content.js`

4. **La interfaz del skill es `SKILL.md`**.
   Ahí están los usos, ejemplos y la filosofía.

5. **Cómo se carga**:
   - el agente lee el `SKILL.md`
   - usa `{baseDir}/browser-tools/...`
   - el repo trae el paquete completo

6. **Estado en esta máquina**:
   - no vi `~/.pi/agent/skills` instalado localmente
   - lo que sí quedó es la **regla en `AGENTS.md`** para preferir ese skill

7. **Configuración mental que quedó**:
   - tools chicas
   - stdout limpio
   - DOM primero
   - screenshot sólo cuando hace falta
   - batch en una sola eval/IIFE
   - `browser-pick` para selectores ambiguos
   - `browser-content` para contenido legible
   - `browser-cookies` para auth/sesión
   - `--profile` para reutilizar login

Si querés, te digo también **cómo quedaría la instalación ideal en este Pi** para que el skill quede realmente disponible localmente y no solo como regla.


Summary:
## Goal
- Mejorar el tema de Pi para que los mensajes del usuario se distingan mucho más.
- Ordenar y limpiar `AGENTS.md` del repo `pi-config`, quitando redundancias y agregando reglas útiles.
- Explorar el artículo de Mario Zechner sobre “no necesitar MCP” y sacar ideas para el harness setup.

## Constraints & Preferences
- El usuario quiere respuestas breves, directas y en castellano argentino.
- No pedirle el mensaje de commit: elegirlo autónomamente.
- No hacer `push` ni `merge` a `main` sin confirmación explícita.
- Para docs/reportes, usar HTML como entry point; links a archivos extra son opcionales.
- Si hay que abrir el HTML, hacerlo en la laptop, no en el servidor.
- `personal-memory-search` debe cargarse primero cuando la tarea dependa de contexto previo.
- `personal-approval-queue` fue descartada por el usuario como skill deprecada.
- El usuario prefiere autonomía para lo no irreversible.

## Progress
### Done
- [x] Se investigó cómo Pi carga themes y se confirmó que hay soporte oficial para themes custom.
- [x] Se creó `~/.pi/agent/themes/purple-user-bubble.json`.
- [x] Se editó `~/.pi/agent/settings.json` y `/mnt/rpi/pi-config/settings.json` durante la exploración de themes.
- [x] Se parchearon varias copias de `dark.json` y `light.json` dentro de `@mariozechner/pi-coding-agent` para que Pi mostrara `userMessageBg` en `#789ccf`.
- [x] Se detectó que el override real de theme estaba en `/mnt/rpi/pi-config/settings.json` y se dejó `theme: "dark"`.
- [x] Se refactorizó `/mnt/rpi/pi-config/AGENTS.md` para quitar redundancia y ordenar reglas.
- [x] Se agregó la preferencia de usar `personal-memory-search` antes de tareas que dependan de contexto.
- [x] Se ajustó la regla de docs para usar HTML como entry point, con archivos linkeados opcionales, y abrirlo en la laptop.
- [x] Se leyó `~/AGENTS.md` en la laptop para comparar y proponer mejoras.
- [x] Se guardaron memorias durables sobre preferencias de commit autónomo, memory search primero y HTML como entry point.
- [x] Se leyó el artículo `https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/` y se listaron insights/tools.
- [x] Se propusieron mejoras numeradas para el harness setup desde el 19 al 35.

### In Progress
- [ ] Esperar a que el usuario elija cuáles de las ideas del harness quiere profundizar.
- [ ] Si el usuario lo pide, revisar si conviene revertir el parche en `node_modules` y dejar solo el theme oficial.

### Blocked
- [ ] Ninguno explícito en este momento.

## Key Decisions
- **Theme de Pi**: se eligió usar `dark` como base y cambiar solo el fondo de mensajes del usuario a `#789ccf` para conservar el resto del look.
- **`AGENTS.md` canónico**: el archivo fuente quedó en `/mnt/rpi/pi-config/AGENTS.md`.
- **Commit messages**: el agente los elige autónomamente; no se le pide al usuario.
- **Docs**: HTML es el entry point; no se fuerza `.md`.
- **Memory**: usar `personal-memory-search` primero cuando haya dependencia de contexto previo.

## Next Steps
1. Esperar la selección del usuario sobre qué ideas del harness quiere ampliar.
2. Si el usuario quiere, convertir alguna de las sugerencias 19–35 en una propuesta concreta para el setup actual.
3. Si el usuario pide, revisar el diff final de `/mnt/rpi/pi-config/AGENTS.md`.
4. Si el usuario vuelve al tema de Pi, decidir si se limpia el parche profundo en `node_modules` o se deja como workaround.
5. Si el usuario quiere, documentar el setup de harness en un formato más formal.

## Critical Context
- Archivo principal editado: `/mnt/rpi/pi-config/AGENTS.md`
- Theme custom creado: `/home/sebas/.pi/agent/themes/purple-user-bubble.json`
- Configs tocadas durante el proceso: `/home/sebas/.pi/agent/settings.json`, `/mnt/rpi/pi-config/settings.json`
- Themes base parcheados en múltiples copias de `@mariozechner/pi-coding-agent/dist/modes/interactive/theme/{dark.json,light.json}`
- Artículo revisado: `What if you don't need MCP at all?` de Mario Zechner
- Prefijo de numeración pedido para el harness: comenzar desde 19

---

**Turn Context (split turn):**

## Original Request
El usuario pidió extraer de `https://github.com/badlogic/pi-skills` todos los “browser tools” relacionados con los ítems `1,2,3,20,30` y con `"seguir unix philosophy"`, agregar cualquier detalle no obvio de esos puntos, y deduplicar todo lo posible contra el `AGENTS` actual.

## Early Progress
- Se interpretó que había que revisar el repositorio `badlogic/pi-skills` para identificar los puntos relevantes.
- Se inició una exploración del repo usando `curl` contra la GitHub API y la página web del árbol del repo.
- La respuesta de la API mostró que el repo contiene al menos `.gitignore`, `LICENSE` y `README.md`; el resto del listado quedó truncado.
- La página HTML de GitHub se descargó también, presumiblemente para buscar contenido adicional si hacía falta.

## Context for Suffix
- La siguiente parte de la interacción probablemente continúa con la inspección del contenido del repo, especialmente `README.md` u otros archivos para extraer las herramientas/indicaciones pedidas.
- Hay que mantener en mente que el objetivo es combinar esos hallazgos con el `AGENTS` existente, quitando duplicados y conservando sólo lo no obvio.

<read-files>
/home/sebas/.agents/skills/memory-write/SKILL.md
/home/sebas/.npm-global/lib/node_modules/@mariozechner/pi-coding-agent/dist/core/resource-loader.js
/home/sebas/.npm-global/lib/node_modules/pi-session-switch/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json
/home/sebas/.npm-global/lib/node_modules/pi-session-switch/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme/theme.js
/home/sebas/AGENTS.md
/mnt/rpi/pi-config/bin/laptop-read
/mnt/rpi/pi-config/git/github.com/apmantza/pi-free/.pi/skills/pi-extension-dev/SKILL.md
/mnt/rpi/pi-config/git/github.com/apmantza/pi-free/node_modules/@mariozechner/pi-coding-agent/docs/themes.md
</read-files>

<modified-files>
/home/sebas/.npm-global/lib/node_modules/pi-session-switch/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme/dark.json
/home/sebas/.npm-global/lib/node_modules/pi-session-switch/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme/light.json
/home/sebas/.pi/agent/settings.json
/home/sebas/.pi/agent/themes/purple-user-bubble.json
/mnt/rpi/pi-config/AGENTS.md
/mnt/rpi/pi-config/settings.json
</modified-files>


Ahí, ahí me parecen dos filosofías, bueno a ver más, pero que es seguir con el uso de skills que lo que hace supuestamente es cargar en contexto todos los frontmatter con que dan nombre y descripción de cada herramienta. Entonces, tenemos que tener herramientas dispersas y cargar en contexto a través de agents donde está cada una y su nombre y skill. Dime si la diferencia que marca real si hay alguno más y que opina. Mario , el autor de las tools de browser y otra gente en internet al respecto.


---
name: personal-memory-search
description: Search persisted research memory, claims, and tasks
---

# personal-memory-search

## Workflow

1. Execute:
   - `curl -fsSL "${AGENTS_DB_API:-http://100.116.176.16:8091}/api/search?q=<query>&scope=global&scope=project&limit=20"`
2. Return matching runs, claims, and tasks from the JSON response.
3. Prefer reuse of prior work before starting a new run.


curl -fsSL 'http://100.116.176.16:8091/api/search?q=browser-tools%20pi-skills%20Mario%20Zechner%20MCP%20skills%20unix%20philosophy&scope=global&scope=project&limit=20' | sed -n '1,240p'