Skip to main content

AI Models & Tools

This document describes HAWKI's AI model registry and tool system: how models and providers are configured and persisted, how tools are registered and executed, and how tools are connected to specific models.

Table of Contents

  1. Overview
  2. Deployment Quick Start
  3. AI Model System
  4. Tool System
  5. Model–Tool Assignments
  6. Database Schema
  7. Service Providers
  8. Command Reference
  9. How-To Guides

Overview

HAWKI's AI model and tool system is split into two complementary layers:

LayerSource of truthPurpose
Configconfig/model_providers.php + config/model_lists/*.php + config/tools.phpDefines available models, providers, and tool classes. Used only at deployment time to populate the database.
Databaseai_providers, ai_models, ai_tools, mcp_servers, ai_model_toolsSingle source of truth at runtime. Persists model registry, online status, all tools, and tool–model assignments.

Config files are never read at runtime for tools or models. After the initial sync, the database contains everything the application needs.


Deployment Quick Start

Follow these steps in order when setting up HAWKI for the first time, or when adding new providers, models, or tools.

Step 1 — Initial database setup

Run migrations. The first-run hook in AppServiceProvider will automatically sync models and function tools as soon as the tables are created:

php hawki migrate

At this point the ai_models and ai_tools tables are populated automatically from your config files.

Step 2 — Verify model sync

php hawki models list

All providers and models from your config files should be visible. If the list is empty or incomplete, run the sync explicitly:

php hawki models sync

Step 3 — Configure providers and default models

In your .env file, enable the providers you need and set their API keys:

# Enable providers
OPENAI_ACTIVE=true
OPENAI_API_KEY=your-key

GWDG_ACTIVE=true
GWDG_API_KEY=your-key

GOOGLE_ACTIVE=true
GOOGLE_API_KEY=your-key

# Set defaults
DEFAULT_MODEL=gpt-4.1-nano
DEFAULT_WEBSEARCH_MODEL=gemini-2.0-flash
DEFAULT_FILEUPLOAD_MODEL=qwen3-omni-30b-a3b-instruct
DEFAULT_VISION_MODEL=qwen3-omni-30b-a3b-instruct

After editing .env, clear the config cache and re-sync so the database reflects your changes:

php hawki clear-cache
php hawki models sync --force

Step 4 — Sync function tools (if not done automatically)

If function tools were not auto-synced (e.g. the table was already populated from a previous install), sync them manually:

php hawki tools sync --function-only

Verify:

php hawki tools list

Step 5 — Add MCP servers (optional)

If you use external MCP servers, add them interactively:

php hawki tools add-mcp-server https://your-mcp-server.example.com/mcp

Or for CI/CD pipelines, add the server to config/tools.php and sync:

php hawki tools sync --mcp-only

Step 6 — Assign tools to models

php hawki tools assign

Follow the interactive prompts, or use direct flags:

php hawki tools assign --tool=my-tool --model=gpt-4.1

Step 7 — Start the application

# Development
php hawki run -dev

# Production build
php hawki run -build

AI Model System

Configuration Layer

Every AI provider and its models are declared in two levels of configuration files.

Provider configuration — config/model_providers.php

Defines global defaults, system models, and a list of providers:

'default_models' => [
'default_model' => env('DEFAULT_MODEL', 'gpt-4.1-nano'),
'default_web_search_model' => env('DEFAULT_WEBSEARCH_MODEL', 'gemini-2.0-flash'),
'default_file_upload_model'=> env('DEFAULT_FILEUPLOAD_MODEL', 'qwen3-omni-30b-a3b-instruct'),
'default_vision_model' => env('DEFAULT_VISION_MODEL', 'qwen3-omni-30b-a3b-instruct'),
],

'system_models' => [
'title_generator' => env('TITLE_GENERATOR_MODEL', 'gpt-4.1-nano'),
'prompt_improver' => env('PROMPT_IMPROVEMENT_MODEL', 'gpt-4.1-nano'),
'summarizer' => env('SUMMARIZER_MODEL', 'gpt-4.1-nano'),
],

'providers' => [
'openAi' => [
'active' => env('OPENAI_ACTIVE', true),
'api_key' => env('OPENAI_API_KEY'),
'api_url' => env('OPENAI_URL', 'https://api.openai.com/v1/responses'),
'ping_url' => env('OPENAI_PING_URL', 'https://api.openai.com/v1/models'),
'models' => require __DIR__ . '/model_lists/openai_models.php',
],
// ... gwdg, google, ollama, openWebUi
]

Provider API keys are never stored in the database; they always come from environment variables.

Model list files — config/model_lists/*.php

Each file returns an array of model definitions:

// config/model_lists/openai_models.php
return [
[
'active' => env('MODELS_OPENAI_GPT4_1_ACTIVE', true),
'id' => 'gpt-4.1',
'label' => 'OpenAI GPT 4.1',
'input' => ['text', 'image'],
'output' => ['text'],
'tools' => [
'stream' => true,
'file_upload' => true,
'vision' => true,
'tool_calling' => true, // set false to exclude from tool assignments
'web_search' => 'native',
'knowledge_base' => 'native',
],
'default_params' => [
'temp' => env('MODELS_OPENAI_GPT4_1_PARAMS_TEMP', 1.0),
'top_p' => env('MODELS_OPENAI_GPT4_1_PARAMS_TOP_P', 1.0),
],
],
// ...
];

Model capability flags (tools array):

KeyValuesMeaning
streamtrue / falseWhether the model supports streaming
file_uploadtrue / falseWhether the model can receive uploaded files
visiontrue / falseWhether the model can process images
tool_callingtrue / falseWhether the model supports function/tool calling. Omitting defaults to true. Set to false to exclude the model from all tool assignments.
web_search'native' / 'unsupported'Whether the provider handles web search natively
knowledge_base'native' / stringStrategy for knowledge-base retrieval
<capability_key>stringName of a registered tool capability the model may invoke

Database Registry

The database mirrors the config-defined providers and models so that the system has a persistent, queryable record of every known model. This enables:

  • Model online-status tracking
  • Tool–model relationship management
  • Admin tooling (listing, deactivating models without changing config files)

The three relevant Eloquent models are:

ClassTableRole
App\Models\Ai\AiProviderai_providersOne row per provider (e.g. openAi, gwdg)
App\Models\Ai\AiModelai_modelsOne row per model definition
App\Models\Ai\AiModelStatusai_model_statusesLive online/offline status, keyed by model_id

Eloquent relationships

AiProvider  ──< hasMany     ── AiModel
AiModel ── hasOne ── AiModelStatus (via model_id string)
AiModel ──< BelongsToMany >── AiTool (pivot: ai_model_tools)
AiTool ── belongsTo ── McpServer (nullable for function tools)
McpServer ──< hasMany ── AiTool

Model Sync

AiModelSyncService

Location: app/Services/AI/Db/AiModelSyncService.php

$syncService->sync();      // sync all providers + models from config → DB
$syncService->isSynced(); // true when ai_models table has at least one row

Sync rules:

  • Providers and models are created or updated (updateOrCreate).
  • Existing database records are never deleted — operators may deactivate a model in the DB independently of config.
  • The active flag is always overridden from config so that environment-variable changes take effect on the next sync.

Automatic first-run sync

AppServiceProvider::boot() calls the sync automatically once when running in a CLI context and the ai_models table is empty:

php hawki migrate          # tables created → models and function tools synced automatically
php hawki models sync # explicit re-sync at any time
php hawki models sync --force # force re-sync even if models already exist

After changing .env model settings, always clear the config cache and re-sync:

php hawki clear-cache
php hawki models sync --force

Model Online Status

Each model's availability is tracked in ai_model_statuses with three possible states:

StatusMeaning
ONLINEProvider API responded successfully
OFFLINEProvider API unreachable or returned an error
UNKNOWNStatus has never been checked

The scheduled command check:model-status runs every 15 minutes. You can also trigger it manually:

php hawki models check-status
# artisan equivalent: php artisan check:model-status

Value Object vs Eloquent Model

The codebase contains two classes named AiModel that serve different purposes:

ClassLocationRole
App\Services\AI\Value\AiModelService layerValue object — wraps a raw config array. Used by AiFactory, AiService, all providers and request converters.
App\Models\Ai\AiModelEloquent layerDatabase model — maps to the ai_models table. Used for DB persistence, admin commands, and tool assignments.

The service layer never uses the Eloquent AiModel directly.


Tool System

Architecture: DB-First

The tool system follows a strict deployment-time / runtime separation:

DEPLOYMENT TIME  (once, per install or when adding new tools)
config/tools.php

php hawki tools sync

├─ ai_tools (type=function, class_name=FQCN)
└─ mcp_servers + ai_tools (type=mcp)

RUNTIME (every request)
ToolServiceProvider::boot()

AiTool::where('active', true)... ← DB only, config never read
├─ type=function → instantiate by class_name → ToolRegistry
└─ type=mcp → DynamicMCPTool wrapper → ToolRegistry

config/tools.php is only read by the ai:tools:sync command and is never consulted at runtime.


Tool Types

HAWKI supports two categories of tools:

TypeStorageExecutionIdentified by
Function-callingai_tools (type=function, class_name=FQCN)Runs locally in the PHP processclass_name column
MCPai_tools (type=mcp) + mcp_serversProxied to an external MCP server over HTTPserver_id FK

Tool Registry

App\Services\AI\Tools\ToolRegistry is a singleton populated during application boot by ToolServiceProvider. It holds all active, enabled tool instances in memory keyed by tool name.

$registry = app(ToolRegistry::class);

$registry->has('test_tool'); // bool
$result = $registry->execute('test_tool', $args, $callId); // ToolResult
$registry->getAll(); // array<string, ToolInterface>

Function-Calling Tools

These are PHP classes that implement ToolInterface and run entirely inside the application.

Interface

interface ToolInterface
{
public function getName(): string;
public function getDefinition(): ToolDefinition;
public function getCapability(): string; // defaults to Str::snake(getName())
public function execute(array $arguments, string $toolCallId): ToolResult;
}

getCapability() returns the key that appears in the model's tools array (e.g. web_search, knowledge_base). The default implementation in AbstractTool returns Str::snake($this->getName()). Override it in your tool class when you need a specific capability key. For instance, if you want to create a new web search tool for specific models or providers, setting the capability to web_search prevents duplicate tool selection entries in the UI, and the frontend only requests the available web search tool for that particular model.

Creating a new function-calling tool

1. Create the class in app/Services/AI/Tools/Implementations/:

namespace App\Services\AI\Tools\Implementations;

use App\Services\AI\Tools\AbstractTool;
use App\Services\AI\Tools\Value\ToolDefinition;
use App\Services\AI\Tools\Value\ToolResult;

class MyCustomTool extends AbstractTool
{
public function getName(): string { return 'my_custom_tool'; }

public function getDefinition(): ToolDefinition
{
return new ToolDefinition(
name: 'my_custom_tool',
description: 'Describe what this tool does for the model.',
parameters: [
'type' => 'object',
'properties' => [
'query' => ['type' => 'string', 'description' => 'The input value'],
],
'required' => ['query'],
]
);
}

public function execute(array $arguments, string $toolCallId): ToolResult
{
$result = ['answer' => 'Processed: ' . ($arguments['query'] ?? '')];
return $this->getSuccessResult($result, $toolCallId);
}
}

getCapability() is inherited from AbstractTool and will return my_custom_tool by default. Override it if you need a different key.

    public function getCapability(): string { return 'custom_capability'; }

2. Add it to config/tools.php:

'available_tools' => [
\App\Services\AI\Tools\Implementations\MyCustomTool::class,
],

3. Sync to the database:

php hawki tools sync --function-only

4. Assign it to models:

php hawki tools assign --tool=my_custom_tool

5. Enable it in the model's config by adding the capability key to the model's tools array:

// config/model_lists/openai_models.php
'tools' => [
'stream' => true,
'my_custom_tool' => 'my_custom_tool', // key must match getCapability()
],

MCP Tools

MCP (Model Context Protocol) tools communicate with external HTTP servers. HAWKI acts as an MCP client and proxies tool calls to the remote server.

MCP Server record

Each server is stored in the mcp_servers table:

FieldDescription
urlHTTP endpoint (unique)
server_labelShort identifier used to prefix tool names (e.g. hawki-rag)
descriptionHuman-readable description
require_approvalnever / always / auto
timeoutExecution timeout (seconds)
discovery_timeoutTimeout used during tool discovery
api_keyOptional Bearer token — stored encrypted using Laravel's Crypt (AES-256-CBC via APP_KEY)

Security note: MCP server API keys are never stored in plaintext. The McpServer Eloquent model declares 'api_key' => 'encrypted' in its $casts, so encryption and decryption are fully transparent. Rotating the APP_KEY will invalidate stored keys — re-enter them via php hawki tools configure-server after a key rotation.

AiTool record

Each tool exposed by an MCP server is stored in the ai_tools table:

FieldDescription
namePrefixed tool name: {server_label}-{mcp_tool_name}
class_namenull for MCP tools (only populated for function tools)
descriptionTool description from the MCP server
inputSchemaJSON Schema for the tool's parameters
capabilityCapability key exposed to the model config
server_idFK to mcp_servers
typemcp
statusactive / inactive — system-managed, set by ai:tools:check-status
activetrue / false — user-managed toggle, set via ai:tools:configure

Adding an MCP server

Option A — Interactive command (recommended for first-time setup):

php hawki tools add-mcp-server https://my-mcp-server.example.com/mcp

The command will:

  1. Prompt for label, description, approval mode, timeouts, and optional API key.
  2. Create a McpServer record.
  3. Connect to the server and list all available tools.
  4. Let you select which tools to register as AiTool records and assign a meaningful capability key to each.
  5. Optionally assign those tools to AI models.

Option B — Config-driven sync (recommended for deployment pipelines):

Add the server to config/tools.php:

'mcp_servers' => [
'my-server' => [
'url' => env('MY_MCP_SERVER_URL', 'https://my-mcp-server.example.com/mcp'),
'server_label' => 'my-server',
'description' => 'My MCP Server',
'require_approval' => 'never',
'timeout' => 30,
'discovery_timeout' => 90,
'api_key' => env('MY_MCP_API_KEY'),
],
],

Then run:

php hawki tools sync --mcp-only

Capability warning: When syncing via config, capability keys are auto-generated from tool names. The sync command will print a warning listing all affected tools and prompt you to set meaningful capabilities using php hawki tools configure.

MCP execution flow

AiService
└─ ToolExecutionService::buildFollowUpRequest()
└─ ToolRegistry::execute('hawki-rag-search', $args, $callId)
└─ DynamicMCPTool::execute()
└─ AbstractMCPTool::execute()
└─ DynamicMCPTool::executeMCP()
└─ MCPSSEClient::callTool() → HTTP JSON-RPC → MCP Server

Tool naming convention

All MCP tool names are prefixed with the server label to avoid collisions:

{server_label}-{mcp_tool_name}

Example: "search" on server "hawki-rag" → "hawki-rag-search"

Tool Status vs Active State

Every tool in ai_tools has two independent boolean signals:

FieldTypeManaged byMeaning
status'active' / 'inactive'System (scheduler)Whether the tool's MCP server is currently reachable. Set automatically by ai:tools:check-status. Function tools always remain active.
activetrue / falseOperatorWhether the tool is intentionally enabled. Set manually via ai:tools:configure. Disabling here removes the tool from the registry without deleting it.

Both conditions must be satisfied for a tool to be loaded into the ToolRegistry at boot:

loaded = (active = true) AND (status = 'active' OR CHECK_TOOL_STATUS = false)

The CHECK_TOOL_STATUS env flag can be set to false to skip the status filter entirely — useful during development when MCP servers may be temporarily offline.


Model–Tool Assignments

The ai_model_tools pivot table links specific AI models to the tools they are permitted to use. Only models with tool_calling set to true (or unset, which defaults to true) in their config are eligible for tool assignments.

Pivot columns

ColumnDescription
ai_model_idFK to ai_models.id
ai_tool_idFK to ai_tools.id
typeTool type (mcp, function)
source_idOptional external reference

Managing assignments

php hawki tools assign --list                                             # view all assignments
php hawki tools assign # interactive
php hawki tools assign --tool=hawki-rag-search --model=gpt-4.1 # direct assignment
php hawki tools assign --tool=hawki-rag-search --provider=openAi # assign to all OpenAI models
php hawki tools assign --tool=hawki-rag-search --model=gpt-4.1 --detach # remove assignment

Database Schema

ai_providers
├── id (PK)
├── provider_id (unique string, e.g. "openAi")
├── name
├── active (bool)
├── api_url
└── ping_url

ai_models
├── id (PK)
├── model_id (unique string, e.g. "gpt-4.1")
├── label
├── active (bool)
├── input (json — ["text","image"])
├── output (json — ["text"])
├── tools (json — capability flags map)
├── default_params (json — {temp, top_p})
└── provider_id (FK → ai_providers.id)

ai_model_statuses
├── model_id (PK string, references ai_models.model_id)
└── status (enum: ONLINE | OFFLINE | UNKNOWN)

mcp_servers
├── id (PK)
├── url (unique)
├── server_label
├── version
├── protocolVersion
├── description
├── require_approval ('never' | 'always' | 'auto')
├── timeout
├── discovery_timeout
└── api_key (TEXT — stored encrypted via Laravel Crypt)

ai_tools
├── id (PK)
├── name (unique — "{server_label}-{tool_name}" for MCP; tool name for function)
├── class_name (nullable — FQCN for function tools, null for MCP tools)
├── description
├── inputSchema (json — JSON Schema for parameters)
├── outputSchema (json — optional)
├── capability (string — capability key referenced in model configs)
├── type ('mcp' | 'function')
├── status ('active' | 'inactive' — system-managed, set by ai:tools:check-status)
├── active (bool — user-managed toggle, set by ai:tools:configure)
└── server_id (FK → mcp_servers.id, nullable — null for function tools)

ai_model_tools (pivot)
├── id (PK)
├── ai_model_id (FK → ai_models.id)
├── ai_tool_id (FK → ai_tools.id)
├── type
└── source_id

Service Providers

AppServiceProvider

Located at app/Providers/AppServiceProvider.php.

  • register() — Binds AiModelSyncService and ToolSyncService as singletons.
  • bootAiModelSync() — When running CLI and ai_models is empty, automatically runs AiModelSyncService::sync().
  • bootToolSync() — When running CLI and ai_tools is empty, automatically runs ToolSyncService::syncFunctionTools(). This ensures function tools are populated on first install without requiring a manual step. MCP servers are not auto-synced here (they require network access) — run php hawki tools sync --mcp-only manually.

ToolServiceProvider

Located at app/Providers/ToolServiceProvider.php.

Loads tools from the database into the ToolRegistry on every boot:

AiTool::with('server')
->where('active', true) // always applied — user's kill switch
->active() // conditionally: status = 'active'
->get()
->each(fn($tool) => match($tool->type) {
'function' => register via class_name,
'mcp' => register as DynamicMCPTool,
});

If the database is unavailable (e.g. during initial migrate), the entire block is silently skipped.

ToolSyncService

Located at app/Services/AI/Db/ToolSyncService.php.

Mirrors the AiModelSyncService pattern for tools:

$syncService->syncFunctionTools();  // reads config/tools.available_tools → ai_tools
$syncService->syncMcpServers(); // reads config/tools.mcp_servers → mcp_servers + ai_tools
$syncService->isSynced(); // true when ai_tools has at least one row

MCP servers that are unreachable during syncMcpServers() are skipped — they are not written to the database. The return value includes a servers_failed array with the reason for each skipped server.


Command Reference

All commands are run via php hawki — thin passthrough wrappers around Laravel Artisan. Both forms are equivalent; php hawki is preferred for convenience.

php hawki [command]         # preferred
php artisan [command] # equivalent alternative

Model commands

php hawki commandArtisan equivalentDescription
models syncai:models:syncSync providers and models from config into the database
models sync --forceai:models:sync --forceRe-sync even when records already exist
models listai:models:listList all models stored in the database
models list --provider=gwdgai:models:list --provider=gwdgFilter by provider
models list --activeai:models:list --activeShow only active models
models list --jsonai:models:list --jsonOutput as JSON
models check-statuscheck:model-statusCheck and update live status of all models (scheduled every 15 min)

Tool sync commands

php hawki commandArtisan equivalentDescription
tools syncai:tools:syncSync all tools from config into the database
tools sync --forceai:tools:sync --forceRe-sync even when tools already exist
tools sync --function-onlyai:tools:sync --function-onlyOnly sync function-calling tools
tools sync --mcp-onlyai:tools:sync --mcp-onlyOnly sync MCP servers and their tools

Tool management commands

php hawki commandArtisan equivalentDescription
tools listai:tools:listList all tools from DB with active/status and model assignments
tools list --jsonai:tools:list --jsonOutput as JSON
tools configureai:tools:configureInteractively configure a tool (capability, description, active toggle)
tools configure --tool={name}ai:tools:configure --tool={name}Configure a specific tool directly
tools assignai:tools:assignInteractively assign/detach tools to models
tools assign --listai:tools:assign --listShow all current tool–model assignments
tools assign --tool={name} --model={id}ai:tools:assign --tool={name} --model={id}Assign directly by name
tools assign --tool={name} --provider={id}ai:tools:assign --tool={name} --provider={id}Assign to all eligible models in a provider
tools assign --detach --tool={name} --model={id}ai:tools:assign --detach ...Remove an assignment
tools check-statusai:tools:check-statusPing all MCP servers, update tool status field (scheduled every 15 min)

MCP server commands

php hawki commandArtisan equivalentDescription
tools add-mcp-server {url}ai:tools:add-mcp-server {url}Add an MCP server, discover tools, assign to models
tools configure-serverai:tools:configure-serverInteractively configure a server's attributes
tools configure-server --server={label|id}ai:tools:configure-server --server=...Configure a specific server directly
tools list-mcp-serversai:tools:list-mcp-serversList all registered MCP servers
tools list-mcp-servers --jsonai:tools:list-mcp-servers --jsonOutput as JSON
tools remove-mcp-serverai:tools:remove-mcp-serverRemove an MCP server and cascade-delete its tools
tools remove-mcp-server {id} --forceai:tools:remove-mcp-server {id} --forceRemove without confirmation prompt

Getting help

php hawki tools help
php hawki models help
php hawki help

How-To Guides

Add a new AI provider

  1. Create config/model_lists/myprovider_models.php following the structure of the existing list files.
  2. Add the provider entry to config/model_providers.php.
  3. Implement the provider adapter in app/Services/AI/Providers/Myprovider/.
  4. Run php hawki models sync --force.

Activate or deactivate a model without touching source code

# In .env
MODELS_OPENAI_GPT5_ACTIVE=false

# Clear cache and re-sync
php hawki clear-cache
php hawki models sync --force

Add a function-calling tool

  1. Create the class extending AbstractTool in app/Services/AI/Tools/Implementations/.
  2. Add it to config/tools.available_tools.
  3. Run php hawki tools sync --function-only.
  4. Assign it to models: php hawki tools assign.
  5. Add the capability key to the model's tools array in the model list config.

Add an MCP server interactively

php hawki tools add-mcp-server https://my-server.example.com/mcp

Follow the prompts to set the label, timeouts, API key (stored encrypted), and assign tools to models.

Add an MCP server via config (CI/CD pipeline)

  1. Add the server to config/tools.mcp_servers with the URL in .env.
  2. Run php hawki tools sync --mcp-only.
  3. Update capability keys: php hawki tools configure --tool={name} for each tool that shows a capability warning.
  4. Assign tools to models: php hawki tools assign.

Disable a tool temporarily without deleting it

php hawki tools configure --tool=my-server-my-tool
# Toggle "active state" when prompted → set to disabled

The tool remains in the database but is excluded from the ToolRegistry on the next boot.

Re-enable a disabled tool

php hawki tools configure --tool=my-server-my-tool
# Toggle "active state" → set to enabled

Update an MCP server's API key

php hawki tools configure-server --server=my-server
# Choose "Update API key?" → enter the new key (stored encrypted automatically)

Update an MCP server's URL

php hawki tools configure-server --server=my-server
# Choose "Update URL?" → enter the new URL
# The command will warn that existing tools may need re-discovery
# Then re-discover tools:
php hawki tools sync --mcp-only --force

Verify which tools a model will receive in a request

The provider-side request converters (ToolAwareConverter trait) build the tools list by:

  1. Reading the tools capability map from the model's config.
  2. Looking up each named capability in the ToolRegistry.
  3. Passing the ToolDefinition (name, description, JSON schema) to the provider API.

Only tools that are both listed in the model config and present in the ToolRegistry are sent to the API.

# Check what's in the registry and assigned to models:
php hawki tools list
php hawki tools assign --list

Rotate APP_KEY (re-encrypt MCP API keys)

If you rotate APP_KEY, stored MCP API keys become unreadable. Re-enter them for each server:

php hawki tools list-mcp-servers
php hawki tools configure-server --server={label}
# Update API key for each server that has one

For further details on individual components see: