Security

Credential vault, license management, permissions, and the triage state machine.

Credential Vault

The vault provides per-plugin encrypted storage for API keys, tokens, and other secrets. Data is encrypted at rest with AES-256-GCM and scoped to the calling plugin — one plugin cannot access another plugin's secrets.

Store a Secret

engine.vault_store(key, value) → bool
engine.vault_store("my_api_key", "sk-abc123...")
# Encrypted at rest, scoped to this plugin

Retrieve a Secret

engine.vault_retrieve(key) → str | None
key = engine.vault_retrieve("my_api_key")
if key:
    # Use the decrypted value
    headers = {"Authorization": f"Bearer {key}"}

Delete a Secret

engine.vault_delete(key) → bool

License Management Coming Soon

ANIMA will support tiered licensing with signed offline license keys. Plugins will be able to check the active license to enable or disable features. This system is under development.

engine.get_license_info() → dict
engine.check_feature(feature) → bool

Permissions

Plugins declare required permissions in plugin.toml. The core enforces these at runtime.

# In plugin.toml
[plugin.permissions]
network = ["api.example.com"]       # allowed external endpoints
filesystem = ["read:corpus/"]       # beyond own data dir
subprocess = false                  # can it spawn subprocesses?
engine.check_permission(plugin_id, action, target, config?) → bool
Checks whether a plugin has permission for a specific action.
if engine.check_permission("my-plugin", "network", "api.example.com"):
    # Allowed to make this network call
    pass

Permission Types

PermissionDescription
networkAllowed external endpoints (beyond ANIMA core)
filesystemFile access beyond the plugin's own data directory
subprocessWhether the plugin can spawn subprocesses

Triage State Machine Rust

The triage state machine validates every new belief before it enters the knowledge graph. This includes beliefs from document extraction, dream synthesis, and manual injection.

Pipeline

The triage runs as a multi-step state machine. At each step, the Rust core returns what it needs, Python performs the side effect (LLM call, semantic search), and resumes the state machine with the result.

StepWhat HappensResume Method
NeedsTranslationPython translates via LLMtriage_resume_translation(id, translated?)
NeedsClassificationPython classifies via LLMtriage_resume_classification(id, classification)
NeedsRewritePython rewrites narrative to mechanismtriage_resume_rewrite(id, rewrite?)
NeedsContradictionCheckPython searches for conflictstriage_resume_contradictions(id, matches)
NeedsConstraintCheckPython checks hypothesis constraintstriage_resume_constraints(id, matches)
NeedsDuplicateCheckPython checks for duplicatestriage_resume_duplicate(id, is_duplicate)
FinalDecisionAccept, reject, or queue(terminal state)

Starting Triage

engine.start_triage(input, governance) → dict
Starts the triage state machine. Returns {id, step, ...payload}.

Final Decision

The terminal FinalDecision step returns:

{
    "decision": "accept",   # accept | reject | queue
    "code": "PASS",
    "reason": "Passed all quality gates",
}

Quality Validation

engine.validate_quality(statement, source?, product_mode?) → dict
Standalone quality gate. Returns {passes, result, reason}. Useful for pre-checking beliefs without running the full triage.

Debugging

engine.triage_get_trace(id) → list[str]
Returns the debug trace log for a triage decision. Useful for understanding why a belief was rejected.
engine.triage_sweep_expired() → int
Cleans timed-out triage states. Returns count of expired states cleaned.

Rust Core Security Methods Rust

MethodReturnsNotes
vault_store(plugin_id, key, value)boolAES-256-GCM encrypted
vault_retrieve(plugin_id, key)str | NonePer-plugin isolated
vault_delete(plugin_id, key)bool
get_license_info()dictComing soon
check_feature(feature)boolComing soon
check_permission(plugin_id, action, target, config?)boolNetwork/filesystem/subprocess