Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Core declaration blocks

5.1 @plugins#

scaicore
1
2
3
4
5
6
7
8
9
@plugins {
    crm = company/salesforce@1.0 {
        instance = "production"
        api_version = "v58"
    }
    ocr = scailabs/document-ocr@2.0
    scaidrive = scailabs/scaidrive@1.0
    erp = company/exact-online@3.0
}

5.2 @llm / @models — AI Model Declarations#

@models is the preferred form; @llm is accepted for backward compatibility. Both are identical in behavior. Each entry declares a named model role with provider, model identifier, and modality configuration.

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@models {
    // Text completion / reasoning models
    primary = {
        provider = "scaigrid"           // "scaigrid" | "openai"
        model = "scailabs/poolnoodle-omni"
        temperature = 0.5
        role = "general"
        modalities = [:text, :structured_output, :vision]
        fallback = [
            { provider = "scaigrid", model = "scailabs/poolnoodle-turbo" }
        ]
    }
    fast = {
        provider = "scaigrid"
        model = "scailabs/poolnoodle-mini"
        temperature = 0.3
        role = "utility"
        modalities = [:text, :structured_output]
        use_when = "classification, simple extraction, tagging"
    }
    creative = {
        provider = "scaigrid"
        model = "scailabs/poolnoodle-omni"
        temperature = 0.9
        role = "creator"
        modalities = [:text]
    }
    critic = {
        provider = "scaigrid"
        model = "scailabs/poolnoodle-omni"
        temperature = 0.2
        role = "reviewer"
        modalities = [:text, :structured_output]
    }

    // Non-text modalities
    voice = {
        provider = "scaigrid"
        model = "scai-tts-1"
        role = "voice"
        modalities = [:tts]
    }
    transcriber = {
        provider = "openai"
        model = "whisper-1"
        role = "transcription"
        modalities = [:stt]
    }
    embedder = {
        provider = "scaigrid"
        model = "scai-embed-1"
        role = "embedding"
        modalities = [:embedding]
    }
}

When provider is omitted, defaults to "scaigrid". When modalities is omitted, defaults to [:text, :structured_output]. See Model Provider spec for the full provider interface and supported modalities.

5.3 @memory#

Persistent state owned exclusively by the instance. For :entity Cores, each entity key gets its own partition. For :stateless Cores, memory is per-Core (one partition, atomic ops). For :singleton, one partition.

No instance can access another instance's memory.

scaicore
1
2
3
4
5
@memory {
    vendor_aliases: map[string, string]
    categorization_history: array[CategorizationRecord]
    interaction_count: int
}

Access via memory.* (see §9 Memory API).

5.4 @config#

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@config {
    @param api_endpoint: string {
        description = "CRM API endpoint"
        required = true
    }

    @param max_retries: int = 3 @hot_reload {
        description = "Maximum retry attempts"
        validation = value >= 0 && value <= 10
    }

    @param urgency_threshold: float = 0.7 @runtime_configurable {
        description = "Threshold for urgent escalation"
        validation = value >= 0.0 && value <= 1.0
    }

    @param api_key: string @secret {
        description = "CRM API key"
        required = true
    }

    @param keywords: array[string] = ["urgent", "legal"] @hot_reload @runtime_configurable {
        description = "Keywords that trigger escalation"
    }
}

5.5 @constraints#

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@constraints {
    never = [
        "promise refund > €100 without approval",
        "share customer data with other customers",
        "admit legal liability"
    ]
    always = [
        "log all interactions to CRM",
        "identify customer before discussing account details",
        "respect GDPR data access/deletion requests"
    ]
    prefer = [
        "resolve without escalation when possible",
        "de-escalation over defensiveness"
    ]
}

5.6 @conversation_policy#

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@conversation_policy {
    routing = {
        match_strategy = "flexible"
        match_on = [sender, session_id, topic_similarity]
        similarity_threshold = 0.8
        no_match = "new_conversation"
    }

    context = {
        always = [customer.profile, customer.tier]
        if_relevant = [customer.billing_status, customer.recent_tickets(30d)]
        on_demand = [customer.full_history]
        max_history_turns = 50
    }

    timeout = {
        idle = 30m
        absolute = 4h
        idle_warning = 25m
        idle_message = "Are you still there?"
    }

    channels = [chat, email, api, internal]
}

5.7 @reference — Read-Only Reference Data#

Data injected at deployment time. Available to all instances of a Core. Immutable at runtime — no instance can write to it. Replaces the need for shared memory in most cases.

scaicore
1
2
3
4
5
6
@reference {
    faq: map[string, FAQEntry]                   // loaded from faq.json
    product_catalog: array[Product]              // loaded from catalog.json
    escalation_rules: array[EscalationRule]      // loaded from rules.json
    compliance_templates: map[string, Template]  // loaded from templates/
}

Access in flows via reference.*:

scaicore
1
2
3
4
5
6
7
@flow handle_question(customer_id: string, question: string): Response {
    @rigid {
        // Read-only — same for all instances, fast local reads
        relevant_faq = reference.faq.search(question)
        rules = reference.escalation_rules
    }
}

Key properties:

  • Loaded at Core deployment or activation time
  • Source: files in deployment bundle or external URIs
  • Refresh: redeployment or host-level refresh signal
  • Can be cached in-memory (immutable → no invalidation needed)

5.8 @triggers — Trigger Declarations#

Declares how external events map to flows:

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@triggers {
    @webhook invoice_uploaded {
        flow = process_invoice
        method = "POST"
        path = "/webhooks/invoice"
        auth = "hmac"
    }

    @schedule daily_reconcile {
        flow = reconcile_batch
        cron = "0 2 * * *"
        timezone = "Europe/Amsterdam"
    }

    @api process {
        flow = process_invoice
        // Exposed as: POST /cores/{core_id}/flows/process
    }
}

Trigger dispatch is a Host responsibility — the runtime declares triggers, the Host implements the transport (HTTP, cron, etc.).

5.9 @on — Event Subscriptions#

Subscribe to events emitted by other Cores:

scaicore
1
2
3
4
5
6
7
@on invoice_processed from core://invoice-processor {
    flow = record_transaction
}

@on payment_received from core://payment-gateway {
    flow = reconcile_payment
}

Event types can be declared in @core_interface for compile-time type safety. Events are delivered at-least-once with per-source ordering.

5.10 @internal — Internal Flow Marker#

Marks a flow as not reachable from triggers. Internal flows don't need the entity key parameter (they're already running within an instance context):

scaicore
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@internal
@flow build_context(): ConversationContext {
    // Called only via @call from other flows within this Core
    // Does not need customer_id parameter even though
    // this Core is :entity(key = "customer_id")
    @rigid {
        return {
            history: memory.interaction_history.last(10),
            preferences: memory.preferences
        }
    }
}

Updated 2026-05-18 11:03:23 View source (.md) rev 2