# RAG2F — LLM Integration Guide

> Plugin-first kernel for composable Retrieval-Augmented Generation systems.

## Core Modules

RAG2F instance provides these managers:

Each bullet follows this pattern:
- `manager_name` / `public_alias` (responsibility) → representative public methods

- `johnny5` / `input_manager` (input) → `execute_handle_text_foreground()`
- `indiana_jones` / `retrieve_manager` (retrieval) → `execute_retrieve()`, `execute_search()`
- `a_team` / `agent_manager` (agents) → `register()`, `get_default()`, `execute_run()`
- `flux_capacitor` / `task_manager` (task orchestration) → `enqueue()`, `run_once()`, `get_status()`
- `optimus_prime` / `embedder_manager` (embedders) → `get_default()`, `register()`
- `xfiles` / `repository_manager` (repositories) → `execute_register()`, `execute_get()`
- `morpheus` / `plugin_manager` (plugins) → `execute_hook()`, `find_plugins()`
- `spock` / `config_manager` (config) → `get_plugin_config()`, `get_rag2f_config()`

## Installation

```bash
pip install rag2f
```

**Optional plugin dependencies** — install only what you need:

```bash
# Azure OpenAI embedder
pip install rag2f[azure-openai]

# Development tools
pip install rag2f[dev]
```

## Quick Start

```python
from rag2f.core.rag2f import RAG2F

# Async factory (required)
rag2f = await RAG2F.create(
    config_path="config.json",      # optional
    plugins_folder="./plugins/",    # optional
    config={"rag2f": {...}}         # optional dict override
)

# Access managers
rag2f.johnny5                   # Input processing
rag2f.input_manager             # Alias for johnny5
rag2f.indiana_jones             # RAG retrieval/search
rag2f.retrieve_manager          # Alias for indiana_jones
rag2f.a_team                    # Agent registry and execution
rag2f.agent_manager             # Alias for a_team
rag2f.flux_capacitor            # Task orchestration
rag2f.task_manager              # Alias for flux_capacitor
rag2f.optimus_prime             # Embedder registry
rag2f.embedder_manager          # Alias for optimus_prime
rag2f.xfiles                    # Repository registry
rag2f.repository_manager        # Alias for xfiles
rag2f.morpheus                  # Plugin/hook manager
rag2f.plugin_manager            # Alias for morpheus
rag2f.spock                     # Configuration
rag2f.config_manager            # Alias for spock
```

Use the primary manager name when possible, and the alias when you want the stable public
surface that mirrors the facade. Both resolve to the same object in the runtime.

---

## The Result Pattern

All `execute_*` methods return typed Result objects. **Never assume success** — always check status.

```python
result = johnny5.execute_handle_text_foreground(text)

if result.is_ok():
    print(result.track_id)
else:
    print(f"Error [{result.detail.code}]: {result.detail.message}")
```

### Result Structure

```python
class BaseResult:
    status: Literal["success", "error"]
    detail: StatusDetail | None  # present on error or partial success

class StatusDetail:
    code: str      # machine-readable: "empty", "duplicate", "not_found"
    message: str   # human-readable description
    context: dict  # diagnostic data
```

### Status Codes (StatusCode constants)

| Code | Module | Meaning |
|------|--------|---------|
| `EMPTY` | All | Input/query is empty |
| `INVALID` | All | Invalid parameter |
| `NOT_FOUND` | All | Resource not found |
| `DUPLICATE` | Johnny5 | Input already processed |
| `NOT_HANDLED` | Johnny5 | No hook handled input |
| `NO_RESULTS` | IndianaJones | Query returned nothing |
| `ALREADY_EXISTS` | XFiles | Different instance with same ID |
| `CACHE_MISS` | XFiles | Cache lookup failed |

### Factory Methods

```python
# Success
InsertResult.success(track_id="abc123")

# Failure
InsertResult.fail(StatusDetail(code=StatusCode.EMPTY, message="Input is empty"))
```

---

## Execute Methods Reference

### Johnny5 — Input Processing

```python
result = rag2f.johnny5.execute_handle_text_foreground(text)
# Returns: InsertResult(status, track_id, detail)
```

Hooks invoked (in order):
1. `get_id_input_text` — generate/retrieve ID
2. `check_duplicated_input_text` — duplicate check
3. `handle_text_foreground` — actual processing

`track_id` is the public identifier returned to callers. If a plugin uses FluxCapacitor
internally, any mapping from `track_id` to internal task ids remains a plugin concern.

### FluxCapacitor — Task Orchestration

```python
root_task_id = rag2f.task_manager.enqueue(
    plugin_id="my_plugin",
    hook="task_default",
    payload_ref={"repository": "docs", "id": "doc-1"},
)

status = rag2f.task_manager.get_status(root_task_id, include_descendants=True)
```

See [flux_capacitor.txt](./flux_capacitor.txt) for the workflow model, task states,
and status tracking patterns.

### IndianaJones — RAG Retrieval

```python
# Retrieve relevant chunks
result = rag2f.indiana_jones.execute_retrieve(
    query,
    k=10,
    return_mode=ReturnMode.WITH_ITEMS,  # default
    for_synthesize=False  # default
)
# Returns: RetrieveResult(status, query, items: list[RetrievedItem], detail)

# Retrieve + synthesize answer (calls execute_retrieve internally)
result = rag2f.indiana_jones.execute_search(
    query, 
    k=10, 
    return_mode=ReturnMode.MINIMAL  # default; WITH_ITEMS to include chunks
)
# Returns: SearchResult(status, query, response, used_source_ids, items, detail)
```

Hooks invoked:
- `indiana_jones_retrieve` — for execute_retrieve() (also called by execute_search)
- `indiana_jones_synthesize` — for execute_search() after retrieval

### XFiles — Repository Management

```python
# Register repository
result = rag2f.xfiles.execute_register(
    id="users_db",
    repository=my_repo,
    meta={"type": "postgresql", "domain": "users"}
)
# Returns: RegisterResult(status, id, created: bool, detail)

# Get repository
result = rag2f.xfiles.execute_get("users_db")
# Returns: GetResult(status, repository, id, detail)
```

### ATeam — Agent Management

```python
from rag2f.core.dto import AgentRunRequest

# Register during plugin activation
rag2f.a_team.register(
    "writer_plugin.writer",
    adapter,
    plugin_id="writer_plugin",
    is_default=True,
)

# Get a plugin default agent
agent = rag2f.a_team.get_default("writer_plugin")

# Execute
result = rag2f.a_team.execute_run(
    AgentRunRequest(
        input="Draft release notes",
        plugin_id="writer_plugin",
        purpose="draft",
        caller="app.pipeline",
    )
)
```

ATeam prompt hooks:
- `agent_collect_prompt_fragments`
- `agent_finalize_prompt`

### OptimusPrime — Embedder Registry

```python
# Register embedder
rag2f.optimus_prime.register("my_embedder", embedder_instance)

# Get default embedder
embedder = rag2f.optimus_prime.get_default()
vector = embedder.getEmbedding("hello world")
```

---

## Configuration (Spock)

Priority: `ENV > JSON > defaults`

### JSON Structure

```json
{
  "rag2f": {
    "embedder_default": "azure_openai"
  },
  "plugins": {
    "my_plugin": {
      "api_key": "...",
      "endpoint": "..."
    }
  }
}
```

### Environment Variables

Pattern: `RAG2F__<SECTION>__<KEY>__<SUBKEY>`

```bash
RAG2F__RAG2F__EMBEDDER_DEFAULT=azure_openai
RAG2F__PLUGINS__MY_PLUGIN__API_KEY=sk-xxx
```

### Accessing Config

```python
# Core config
value = rag2f.spock.get_rag2f_config("embedder_default")

# Plugin config
config = rag2f.spock.get_plugin_config("my_plugin")
api_key = rag2f.spock.get_plugin_config("my_plugin", "api_key")
```

---

## Plugins

RAG2F is **plugin-first**: the core is minimal, functionality comes from plugins.

### What Plugins Provide

- **Embedders** — registered during plugin activation (OptimusPrime registry)
- **Repositories** — registered during plugin activation (XFiles registry)
- **Processing logic** — hooks for Johnny5, IndianaJones pipelines
- **Custom hooks** — extend any part of the system

### Plugin Discovery Order

Plugins are discovered in this priority order:

1. **Entry points** (pip packages) — HIGHEST PRIORITY. Installed via `pip install rag2f-my-plugin`
2. **Filesystem** (`plugins/` folder) — LOCAL DEVELOPMENT. Located at `./plugins/my_plugin/`

**Entry points win** if the same plugin ID exists in both sources.

### Agent Code Starting Point

If you are implementing a new plugin with a code agent, start with:
- [plugin_agent_playbook.txt](./plugin_agent_playbook.txt)

It compresses the runtime rules that matter most during implementation:
- what must happen in `activated()`
- what belongs in hooks
- how IDs and defaults resolve
- how to verify the plugin actually loaded

### Using Plugins

```bash
# Install plugin
pip install rag2f-azure-openai-embedder
```

```python
# RAG2F auto-discovers installed plugins
rag2f = await RAG2F.create(
    plugins_folder="./plugins/",  # Also checks local folder
    config_path="config.json"
)

# Verify loaded plugins
print(rag2f.morpheus.plugins.keys())
```

### Framework Guides

| Guide | Purpose |
|-------|---------|
| [llms.txt](./llms.txt) | Main integration overview, manager map, result pattern, and links to all framework guides |
| [plugin_agent_playbook.txt](./plugin_agent_playbook.txt) | Fast path for code agents building, validating, or repairing plugins correctly |
| [creating_plugins.txt](./creating_plugins.txt) | Plugin authoring guide with lifecycle, hooks, packaging, and end-to-end examples |
| [using_plugins.txt](./using_plugins.txt) | Install, configure, discover, and verify plugins at runtime from code or packages |
| [a_team.txt](./a_team.txt) | Agent registry contract, prompt orchestration hooks, defaults, and adapter patterns |
| [flux_capacitor.txt](./flux_capacitor.txt) | Background task orchestration, workflow fan-out, status tracking, and worker patterns |
| [indiana_jones.txt](./indiana_jones.txt) | Retrieval and search flow, hook sequence, return types, and synthesis extension points |
| [johnny5.txt](./johnny5.txt) | Input pipeline behavior, duplicate checks, tracking IDs, and foreground handling hooks |
| [morpheus.txt](./morpheus.txt) | Plugin discovery, hook execution rules, priorities, decorators, and lifecycle behavior |
| [observability.txt](./observability.txt) | Structured logging, correlation context, and observability practices for core and plugins |
| [optimus_prime.txt](./optimus_prime.txt) | Embedder registry semantics, default resolution, protocol expectations, and registration rules |
| [spock.txt](./spock.txt) | JSON and ENV configuration model, precedence rules, and plugin config access patterns |
| [testing.txt](./testing.txt) | Testing patterns for hooks, plugins, configs, mocks, and in-memory workflow backends |
| [xfiles.txt](./xfiles.txt) | Repository registry contracts, capabilities, result objects, and native access patterns |
| [exceptions.txt](./exceptions.txt) | Error model for results vs exceptions, extension guidance, and failure semantics |

---

## Error Handling Philosophy

- **Expected states** → Return Result with `status="error"` (no exception)
- **System errors** → Raise exceptions (backend crash, timeout)

This minimizes overhead for common cases (empty input, duplicates) while preserving stack traces for actual bugs.

For the full exception model and implementation guidance, see [exceptions.txt](./exceptions.txt).

---

## Optional

### Testing

See: [testing.txt](./testing.txt)

Quick mock pattern:

```python
from unittest.mock import MagicMock
from rag2f.core.johnny5 import Johnny5

mock_rag2f = MagicMock()
mock_rag2f.morpheus.execute_hook.side_effect = lambda hook_name, *args, **kw: ...
johnny5 = Johnny5(rag2f_instance=mock_rag2f)
```