# AI Assistant Instructions

> Context for AI coding assistants (Claude Code, Cursor, Copilot, Cody, etc.)

This project uses **PenguiFlow v2.7** for agent scaffolding and orchestration.

---

## Project Overview

- **Agent**: {{ agent_name }}
- **Spec File**: `{{ agent_name }}.yaml`
- **Package**: `{{ package_name }}`
- **Template**: Will be set when you run `penguiflow generate`

---

## Workflow

### 1. Edit the Spec

The `{{ agent_name }}.yaml` file defines:
- Agent configuration (name, template, flags)
- LLM settings (provider, model)
- Tools (functions the agent can call)
- Flows (optional multi-step pipelines)
- Planner settings (prompts, limits)

### 2. Generate the Project

```bash
# Validate first
penguiflow generate --spec {{ agent_name }}.yaml --dry-run

# Generate (safe default)
# - Updates spec-synced files (planner/registry/config/README/etc.)
# - Creates missing scaffolds (new tools/flows/tests)
# - Does NOT overwrite existing tool/flow implementations unless you pass --force
penguiflow generate --spec {{ agent_name }}.yaml
```

### 3. Implement Tools

Generated tools are stubs. Find them in `src/{{ package_name }}/tools/`.

---

## Regeneration Safety (Read This Before Using `--force`)

`penguiflow generate` is designed to be incremental: you can keep iterating on the spec and re-run it without losing your implementations.

Use `--force` only when you explicitly want to overwrite existing files (including tool/flow code you may have edited).

If you ever need `--force`:
1. Make sure your work is committed (or at least stashed / copied).
2. Run `--dry-run` first to see what will be touched.
3. Prefer deleting a specific file and re-running without `--force` when you only want to refresh one scaffold.

---

## Key Conventions

### Tool Names
- Must be `snake_case`: `search_documents`, not `searchDocuments`
- Avoid Python reserved words

### Type Annotations
Supported types in spec:
- `str`, `int`, `float`, `bool`
- `list[T]` (e.g., `list[str]`)
- `dict[K, V]` (e.g., `dict[str, int]`)
- `Optional[T]` (e.g., `Optional[int]`)

### Tool Implementation Pattern

```python
from penguiflow.catalog import tool
from penguiflow.planner import ToolContext

@tool(desc="Description shown to LLM", tags=["tag"], side_effects="read")
async def my_tool(args: MyToolArgs, ctx: ToolContext) -> MyToolResult:
    # Access context
    llm_data = ctx.llm_context.get("key")      # Read-only LLM context
    runtime_data = ctx.tool_context.get("key")  # Mutable runtime context

    # Implementation
    result = await do_something(args.param)

    return MyToolResult(output=result)
```

### Side Effects

| Value | Meaning |
|-------|---------|
| `pure` | No side effects, deterministic |
| `read` | Reads external state |
| `write` | Writes/mutates external state |
| `external` | Calls external APIs |
| `stateful` | Maintains internal state |

---

## Common Tasks

### Add a New Tool

1. Add to `{{ agent_name }}.yaml`:
```yaml
tools:
  - name: new_tool
    description: "What this tool does"
    args:
      input_param: str
    result:
      output_field: str
```

2. Regenerate: `penguiflow generate --spec {{ agent_name }}.yaml`

3. Implement in `src/{{ package_name }}/tools/new_tool.py`

**If you later change this tool's `args` / `result` in the spec:**
- Update `src/{{ package_name }}/tools/new_tool.py` manually to match, or
- Delete `src/{{ package_name }}/tools/new_tool.py` and re-run generation to re-scaffold it.

### Add a Flow (Pipeline)

1. Add to `{{ agent_name }}.yaml`:
```yaml
flows:
  - name: my_pipeline
    description: "What this pipeline does"
    nodes:
      - name: step_one
        description: "First step"
      - name: step_two
        description: "Second step"
    steps: [step_one, step_two]
```

2. Regenerate: `penguiflow generate --spec {{ agent_name }}.yaml`

3. Flow and orchestrator generated in `src/{{ package_name }}/flows/`

### Modify System Prompt

Edit `planner.system_prompt_extra` in `{{ agent_name }}.yaml`, then regenerate.

---

## File Locations

| File | Purpose |
|------|---------|
| `{{ agent_name }}.yaml` | Agent specification |
| `src/{{ package_name }}/config.py` | Environment config |
| `src/{{ package_name }}/orchestrator.py` | Main entry point |
| `src/{{ package_name }}/planner.py` | Tool catalog, prompts |
| `src/{{ package_name }}/tools/*.py` | Tool implementations |
| `src/{{ package_name }}/flows/*.py` | Flow definitions |
| `.env` | Environment variables (API keys) |

---

## Commands

```bash
# Generate from spec
penguiflow generate --spec {{ agent_name }}.yaml

# Validate spec without generating
penguiflow generate --spec {{ agent_name }}.yaml --dry-run

# Force regenerate (danger: overwrites existing files, including tool/flow implementations)
# Use only on a clean working tree, or after committing/stashing your changes.
penguiflow generate --spec {{ agent_name }}.yaml --force

# Run the agent
uv run python -m {{ package_name }} "Your query"

# Run tests
uv run pytest
```

---

## Generated vs Developer-Owned Files

### Spec-synced (always regenerated; do not edit)

- `src/{{ package_name }}/planner.py`
- `src/{{ package_name }}/config.py`
- `src/{{ package_name }}/tools/__init__.py`
- `src/{{ package_name }}/flows/__init__.py`
- `src/{{ package_name }}/*_orchestrator.py` (flow orchestrators, if any)
- `README.md`
- `.env.example`
- `ENV_SETUP.md`
- `tests/conftest.py`

### Scaffolds (created when missing; safe to modify)

- `src/{{ package_name }}/tools/*.py` (tool implementations)
- `src/{{ package_name }}/flows/*.py` (flow implementations)
- `tests/test_tools/test_*.py` and `tests/test_flows/test_*.py`
- `src/{{ package_name }}/orchestrator.py` (entrypoint wiring)
- `.env` (your local secrets)

### Notes
- If a scaffold exists, it will not be overwritten unless you pass `--force` (or delete the file first).
- Keep custom code in separate modules and have scaffolds call into them; this makes regeneration safer.

---

## Debugging

### Verbose Generation
```bash
penguiflow generate --spec {{ agent_name }}.yaml --verbose
```

### Check Generated Code Syntax
```bash
python -m py_compile src/{{ package_name }}/tools/*.py
```

### Run Single Tool Test
```bash
uv run pytest tests/test_tools/test_my_tool.py -v
```
