Installs into .claude/skills of the current project.
Are you the author of Agent Programming?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/vectorspacelab-agent-programming)
---
name: agent-programming
description: "Write and debug Browser Use Python agent workflows with legacy
browser_use.Agent and Rust-backed browser_use.beta.Agent, including prompts,
run loops, callbacks, initial_actions, planning, timeouts, flash mode,
history, and API routing."
disable-model-invocation: true
metadata:
disco-role: operating
license: MIT
---
# Agent Programming
Use this sub-skill when the user is writing Python code around Browser Use agents: constructing an agent, designing the task prompt, running it in an async loop, inspecting history, adding callbacks, preloading initial actions, choosing legacy vs beta agent entrypoints, or debugging agent-loop behavior.
## Route Here
- The user imports `Agent` from `browser_use` or `browser_use.beta`.
- The task is about `Agent(...)`, `await agent.run(...)`, `agent.step(...)`, `agent.take_step(...)`, callbacks, stop/pause hooks, history parsing, or prompt design.
- The request mentions `initial_actions`, `max_steps`, `max_failures`, `llm_timeout`, `step_timeout`, `flash_mode`, `enable_planning`, `message_compaction`, `save_conversation_path`, or `generate_gif`.
- The user wants to compare legacy Python agent behavior with the beta Rust-backed agent.
- The user hit a workflow symptom such as empty history, repeated actions, planning not showing, initial navigation failing, final result missing, or `BetaAgentError`.
## Route Elsewhere
- Browser/profile/CDP/session launch settings, real Chrome profiles, downloads, proxies, screenshots, videos, HAR, domains, and low-level Actor APIs belong in `../browser-control/SKILL.md`.
- Custom actions, default tools, file tools, action schemas, `ActionResult`, sensitive data guardrails, and domain/file security belong in `../tools-and-actions/SKILL.md`.
- LLM provider selection, API keys, `ChatBrowserUse`, structured output, extraction models, fallback models, and cost accounting belong in `../llm-and-output/SKILL.md`.
- Terminal `browser-use` or `bu` CLI sessions belong in `../cli-and-sessions/SKILL.md`.
- Cloud sandbox, MCP, skill services, telemetry, hosted production, and integration workflows belong in `../production-integrations/SKILL.md`.
## Entry Point Choice
Prefer the legacy Python agent when the user needs maximum open-source Python extensibility:
```python
from browser_use import Agent, ChatBrowserUse
```
Prefer the beta agent when the user asks for the Rust-backed/core runtime path or is following the 0.13 beta quickstart:
```python
from browser_use.beta import Agent, BrowserProfile, ChatBrowserUse
```
The public package exposes both paths. Existing Python code can keep `from browser_use import Agent`; the beta path is explicitly `from browser_use.beta import Agent` and requires the Browser Use terminal/core runtime to be available.
## Safe Default Agent Pattern
Use an explicit async `main()`, load environment variables outside the skill content, and set a small step limit during debugging:
```python
import asyncio
from browser_use import Agent, ChatBrowserUse
async def main():
agent = Agent(
task="Go to https://example.com and report the page title.",
llm=ChatBrowserUse(),
)
history = await agent.run(max_steps=20)
print(history.final_result() or "No final result")
asyncio.run(main())
```
For new Browser Use automation tasks, recommend `ChatBrowserUse()` as the default model because Browser Use maintains it for browser automation. Do not replace user-specified model names in existing code.
## Prompt Design Checklist
- Make browser tasks explicit: start URL, goal, fields to extract, output format, login assumptions, and fallback path.
- Name default actions when deterministic behavior matters: `navigate`, `click`, `input`, `scroll`, `extract`, `send_keys`, `done`.
- Add recovery instructions for flaky sites: try keyboard navigation, wait/refresh once, use search fallback, or stop with a clear reason.
- Keep credentials out of prompts; use approved sensitive-data or custom-tool patterns from sibling skills.
- For multi-step tasks, ask for intermediate validation and a final `done` result rather than open-ended browsing.
See `references/workflows.md` for reusable recipes.
## Core Constructor Knobs
Use `references/agent-api.md` for parameter details. The most common agent-programming knobs are:
- `task`: natural-language browser objective; include a URL if `directly_open_url=True` should pre-navigate.
- `llm`: model object; when omitted, Browser Use resolves a configured default or creates `ChatBrowserUse()`.
- `initial_actions`: ordered list of action dictionaries executed before model-driven steps.
- `max_failures`, `final_response_after_failure`: controls failure stopping and final recovery call.
- `llm_timeout`, `step_timeout`: separate model-call and per-step/action watchdogs.
- `max_actions_per_step`: lets the model emit multiple actions in a single step.
- `flash_mode`: faster output shape; strips thinking and planning fields and disables planning.
- `enable_planning`, `planning_replan_on_stall`, `planning_exploration_limit`: plan/replan nudges for full-mode agents.
- `register_new_step_callback`, `register_done_callback`, `on_step_start`, `on_step_end`: observe or interrupt run progress.
- `save_conversation_path`, `generate_gif`, `max_history_items`, `message_compaction`: debugging and memory controls.
## Initial Actions
Use `initial_actions` when setup is deterministic and should happen before the model reasons:
```python
initial_actions = [
{"navigate": {"url": "https://example.com", "new_tab": False}},
]
agent = Agent(task="Summarize the landing page", llm=llm, initial_actions=initial_actions)
```
Notes:
- Legacy and beta agents convert action dictionaries through the current tool registry when possible.
- The beta agent preserves the original ordered payloads in task context and maps legacy aliases such as `click_element_by_index` to current action names when possible.
- If `directly_open_url=True` and the task contains a URL, Browser Use can add an initial `navigate` action automatically when no explicit `initial_actions` are supplied.
- Initial actions can time out or fail before any model step; inspect history and `history.errors()`.
## Running and Observing
- Use `history = await agent.run(max_steps=...)` for normal execution.
- Use `on_step_start(agent)` and `on_step_end(agent)` when you need per-step hooks around the run loop.
- Use constructor callbacks for external systems:
- `register_new_step_callback(state, model_output, step_number)` can be sync or async.
- `register_done_callback(history)` can be sync or async.
- `register_should_stop_callback()` and `register_external_agent_status_raise_error_callback()` can stop or fail externally.
- For beta follow-up tasks, call `await agent.follow_up("...", max_steps=...)` only after a successful `run()` created an active Rust session.
## Reading History
`Agent.run()` returns `AgentHistoryList`. Use its helper methods instead of parsing private fields:
```python
history = await agent.run(max_steps=30)
print(history.final_result())
print(history.is_done(), history.is_successful())
print(history.urls())
print(history.action_names())
print(history.errors())
```
Useful helpers include `final_result()`, `is_done()`, `is_successful()`, `has_errors()`, `urls()`, `screenshot_paths()`, `screenshots()`, `action_names()`, `model_actions()`, `model_outputs()`, `model_thoughts()`, `action_results()`, `action_history()`, `extracted_content()`, `number_of_steps()`, `total_duration_seconds()`, and `save_to_file(...)`.
For Pydantic structured output, prefer the sibling model/output guidance. At the agent-programming level, remember that `history.structured_output` only works when the history retains the output model schema; otherwise use `history.get_structured_output(MyModel)`.
## Planning and Flash Mode
- Full-mode output can include thinking, previous-goal evaluation, memory, next goal, current plan item, and plan updates.
- `enable_planning=False` makes plan rendering and plan updates no-ops.
- `flash_mode=True` removes thinking and planning fields from the output schema and forces `enable_planning=False`.
- In the current implementation, a Browser Use provider model automatically enables flash mode; use a non-flash-compatible configuration if the user specifically needs plan fields.
- Replan nudges are soft context messages; they do not block repeated actions.
## Beta/Core Routing
The beta agent is a Python wrapper around a Rust Browser Use terminal SDK server. Use it when the user explicitly asks for beta/core behavior or imports from `browser_use.beta`.
```python
from browser_use.beta import Agent, ChatBrowserUse
agent = Agent(task="Open https://example.com and report the title", llm=ChatBrowserUse())
history = await agent.run(max_steps=20)
```
Beta-specific notes:
- `find_browser_use_terminal_binary()` locates the required terminal binary.
- Missing terminal/core runtime raises `BetaAgentError` with instructions to install Browser Use Terminal/core or set `BROWSER_USE_TERMINAL_BINARY`.
- `run(max_steps=100)` delegates the main loop to the SDK server after Python-side setup and initial actions.
- `take_step(...)` can execute initial actions and then run one SDK step.
- `follow_up(...)` requires an active Rust session from a prior `run()`.
## Validation Commands
Use this portable check when validating agent code or reproducing issues:
```bash
python - <<'PY'
from browser_use import Agent, ChatBrowserUse
from browser_use.beta import Agent as BetaAgent
print(Agent, ChatBrowserUse, BetaAgent)
PY
```
For normal user projects, prefer import/signature smoke checks and small scripts with `max_steps` capped. Run source-checkout test suites only when the user is explicitly maintaining Browser Use itself.
## Troubleshooting First Steps
See `references/troubleshooting.md` for symptoms and fixes. Start with:
- Confirm `browser-use` imports and Chromium/Browser Use terminal dependencies are installed for the chosen agent path.
- Confirm the relevant provider API key is present without printing it.
- Reduce to a minimal `Agent(task="Open https://example.com...", max_steps=5)` script.
- Lower complexity: remove custom tools, structured output, proxies, and persistent profiles until the run loop works.
- Inspect `history.errors()`, `history.action_names()`, and saved conversation logs.
- If initial actions fail, set `step_timeout`, disable automatic URL pre-navigation with `directly_open_url=False`, or make the first navigation explicit.