---
alwaysApply: true
---
# Rules for Narada Development
You are an AI coding assistant helping developers build web automation workflows and custom agents with the Narada Python SDK.
## Current SDK Model
Narada uses an environment + agent design:
- Create an execution target with an environment, such as `BrowserEnvironment`, `CloudBrowserEnvironment`, `RemoteBrowserEnvironment`, or `LambdaEnvironment`.
- Create an `Agent(environment=env, kind=...)`.
- Call `await agent.run(prompt=...)` for natural-language tasks.
- Call browser action helpers on `agent`, such as `go_to_url()`, `agentic_selector()`, `read_google_sheet()`, and `print_message()`.
- Use the environment for lifecycle and IDs, such as `await env.start()`, `env.browser_window_id`, `env.cloud_browser_session_id`, and `await env.close()`.
Do not use older APIs such as `Narada()`, `open_and_initialize_browser_window()`, `LocalBrowserWindow`, `RemoteBrowserWindow`, or `window.agent()`.
## Standalone SDK Script Pattern
```python
import asyncio
from narada import Agent, BrowserEnvironment
async def main() -> None:
env = BrowserEnvironment()
agent = Agent(environment=env)
try:
response = await agent.run(
prompt="Search for Narada AI and summarize the first result.",
)
print(response.text)
finally:
await env.close()
if __name__ == "__main__":
asyncio.run(main())
```
## Agent Studio Python Agent Pattern
In Agent Studio, `BrowserEnvironment()` targets the current browser window through the runtime environment.
```python
from narada import Agent, BrowserEnvironment
env = BrowserEnvironment()
agent = Agent(environment=env)
await agent.go_to_url(url="https://example.com", new_tab=True)
response = await agent.run(
prompt="Extract the main heading from this page.",
)
print(response.text)
```
Use `new_tab=True` for the first navigation in Agent Studio so the workflow runtime tab stays separate from the page being automated.
## Agent Kinds
Choose the agent kind when constructing the agent:
```python
from narada import Agent, AgentKind, BrowserEnvironment
env = BrowserEnvironment()
operator = Agent(environment=env) # Defaults to AgentKind.OPERATOR
core_agent = Agent(environment=env, kind=AgentKind.CORE_AGENT)
custom_agent = Agent(environment=env, kind="/$USER/my-custom-agent")
```
Use `AgentKind.OPERATOR` for browser automation. Use `AgentKind.CORE_AGENT` for read-only reasoning, page summaries, and conversation-style tasks. Use a namespaced string for custom agents from Agent Studio.
## Structured Output
Use Pydantic models with `output_schema` for reliable extraction:
```python
from pydantic import BaseModel, Field
class CompanyInfo(BaseModel):
name: str = Field(description="Company name")
valuation: str = Field(description="Latest known valuation")
source_url: str = Field(description="URL where the valuation was found")
response = await agent.run(
prompt="Extract company valuation data from this page.",
output_schema=CompanyInfo,
)
company = response.structured_output
assert company is not None
```
Prefer `response.text` for text responses and `response.structured_output` for typed responses.
## Navigation and Browser Actions
Use agent methods for browser actions:
```python
await agent.go_to_url(url="https://example.com/products", new_tab=True)
await agent.agentic_selector(
action={"type": "click"},
selectors={"aria_label": "Search"},
fallback_operator_query="click the search button",
)
current_url = await agent.get_url()
print(current_url.url)
```
Prefer resilient selectors such as ARIA labels, `data_testid`, roles, names, and stable text. Always include a clear fallback query.
## Attachments
Pass file-like objects directly to `Agent.run()`. The SDK uploads them automatically.
```python
from narada import AgentKind
document_agent = Agent(environment=env, kind=AgentKind.CORE_AGENT)
with open("financial_report.pdf", "rb") as f:
response = await document_agent.run(
prompt="Summarize the key financial metrics from this report.",
attachment=f,
)
```
Do not call a separate public `upload_file()` method.
## Google Sheets
Read from and write to Google Sheets with agent methods:
```python
sheet_data = await agent.read_google_sheet(
spreadsheet_id="your_sheet_id",
range="Companies!A1:C10",
)
results = []
for row in sheet_data.values:
company_name = row[0]
response = await agent.run(
prompt=f"Find the latest valuation for {company_name}.",
)
results.append([company_name, response.text])
await agent.write_google_sheet(
spreadsheet_id="your_sheet_id",
range="Results!A1:B5",
values=results,
)
```
## Progress Updates
Use `print_message()` for user-visible progress in the Narada side panel:
```python
await agent.print_message(message="Starting data extraction...")
await agent.print_message(message=f"Processed {len(results)} companies")
```
## Error Handling
Handle timeouts and reset agent state before retrying:
```python
from narada import NaradaError, NaradaTimeoutError
try:
response = await agent.run(
prompt="Complete a complex task on this slow page.",
timeout=60,
)
except NaradaTimeoutError:
await agent.reset_agent_state()
response = await agent.run(prompt="Try a simpler version of the task.")
except NaradaError as exc:
print(f"Narada failed: {exc}")
```
## Parallel Execution
Create one environment per independent browser task:
```python
import asyncio
from narada import Agent, BrowserEnvironment
async def analyze_company(company_url: str):
env = BrowserEnvironment()
agent = Agent(environment=env)
try:
await agent.go_to_url(url=company_url, new_tab=True)
return await agent.run(prompt="Extract company valuation data.")
finally:
await env.close()
results = await asyncio.gather(*[
analyze_company(url) for url in company_urls
])
```
## Documentation Workflow
Before writing Narada code:
1. Read the relevant `@Narada` documentation page.
2. Check the current method signature and examples.
3. Plan the environment, agent kind, browser actions, response shape, and cleanup.
4. Implement with `try` / `finally` so environments close cleanly.