TURN Trigger Language (TTL)

Version 0.1.0 · January 2026 · Implementation Specification

1. Overview

The TURN Trigger Language (TTL) formalizes graph-native triggers that enable the Atomic Knowledge Graph to observe itself and actuate responses. This is the mechanism by which the graph watches itself—the core differentiator that makes ADAMAS fundamentally different from static orchestration systems.

TTL unifies data and behavior in the knowledge graph. Rather than separating rules from data, triggers live alongside the atoms they observe. The graph is simultaneously the source of truth, the observer, and the actuator.

2. Design Philosophy

The Self-Mutating Graph

Traditional systems separate data from behavior through external rules engines:

[Data] → [Rules Engine] → [Actions]

TTL unifies them inside the knowledge graph itself:

[Knowledge Graph]
     ↓ observes itself
[TriggerAtom]
     ↓ actuates
[Knowledge Graph mutations + Agent invocations]

Why This Matters

Without TTL, learning is manual: an agent makes an observation, a human reviews it, decides to create a constraint, and manually creates it. Four steps requiring human intervention.

With TTL, learning is autonomous: an agent creates an ObservationAtom, a TriggerAtom fires when confidence ≥ 0.9, a constraint proposal agent launches automatically, a policy validator runs, and only high-impact items need human review. The flywheel spins without human intervention for routine cases.

3. TTL Syntax

Basic Structure

@trigger <WatchedAtomType>
  WHEN <condition>
  [WITH <context_queries>]
  ACTUATE {
    <actuator_chain>
  }
  [CONFIG {
    <configuration>
  }]

Here's a complete example—the observation-to-constraint promotion trigger:

@trigger ObservationAtom
  WHEN confidence >= 0.9
   AND 'limitation' IN tags
   AND occurrence_count >= 3
  WITH {
    related_code: "MATCH (o)-[:ABOUT]->(c:CodeAtom) RETURN c",
    existing_constraints: "MATCH (c:ConstraintAtom) RETURN c.name"
  }
  ACTUATE {
    @agent: {
      query: "AgentAtom WHERE 'constraint_proposer' IN tags",
      prompt: "Propose a constraint based on: {{observation}}",
      tier: "cheap"
    },
    @system: {
      operation: "update",
      target: "PolicyAtom WHERE name = 'constraint_review_queue'",
      data: {pending_reviews: "{{pending_reviews}} + 1"}
    },
    @human: {
      condition: "impact = 'high'",
      prompt: "High-impact constraint proposed: {{constraint_proposal}}",
      timeout: "24h",
      fallback: "escalate"
    }
  }
  CONFIG {
    enabled: true,
    priority: 100,
    debounce: "5s",
    max_fires_per_hour: 10
  }

Condition Syntax

TTL supports simple, compound, and nested conditions:

TypeSyntaxExample
Comparisonfield op valueconfidence >= 0.9
Equalityfield = valuestatus = 'completed'
Containmentfield CONTAINS valuetags CONTAINS 'security'
Patternfield MATCHES patternname MATCHES 'auth_*'
Temporalfield > NOW() - INTERVALupdated_at > NOW() - INTERVAL '1 hour'
ANDcond AND condconfidence >= 0.9 AND tags CONTAINS 'limitation'
ORcond OR condstatus = 'failed' OR retry_count >= 3
NOTNOT condNOT status = 'skipped'
Nested(cond) OR cond(confidence >= 0.9 AND tags CONTAINS 'limitation') OR manual = true

Field Access

TTL supports direct fields, nested fields via dot notation, relationship traversal with bracket syntax, and array indexing:

confidence                           // Direct field
metadata.source                      // Nested field
[ABOUT->CodeAtom].language           // Relationship traversal
tags[0]                              // Array access

4. Actuator Types

TTL provides six actuator types, each serving a distinct role in the trigger response chain.

@agent — Launch Agent Reasoning

Invokes an agent to process the trigger event. Agents can be found by ID or discovered dynamically via graph query.

@agent: {
  // Find agent
  id: "agent_constraint_proposer",
  query: "AgentAtom WHERE 'proposer' IN tags",

  // Prompt
  prompt: "Analyze this: {{observation}}",

  // Execution options
  tier: "cheap" | "expensive" | "adaptive",
  model_override: "claude-sonnet-4-5",
  thinking_budget: 16000,
  token_budget: 5000,

  // Context injection
  inject: ["observation", "related_code", "existing_constraints"]
}

@system — Automatic Rule Evaluation

Performs CRUD operations on the knowledge graph without agent involvement. Supports create, update, delete, and validate operations.

@system: {
  operation: "create" | "update" | "delete" | "validate",

  // For create
  atom_type: "ConstraintAtom",
  data: { name: "{{proposed_name}}", source_observations: ["$atom_id"] },

  // For update
  target: "PolicyAtom WHERE name = 'review_queue'",
  data: { pending_count: "pending_count + 1", last_updated: "NOW()" },

  // For validate
  validation_rules: ["{{new_constraint}} does not conflict with existing"]
}

@human — Require Human Approval

Inserts a human decision point into the actuator chain. Supports conditional execution, timeout handling, and escalation paths.

@human: {
  condition: "impact = 'high' OR cost_usd > 10",
  prompt: "Review this constraint proposal:\n{{constraint_proposal}}",
  options: ["approve", "reject", "modify"],
  timeout: "24h",
  reminder_at: "12h",
  fallback: "approve" | "reject" | "escalate" | "defer",
  escalate_to: "AgentAtom WHERE role = 'architect'",
  notify_channel: "slack://adamas-reviews"
}

@schedule — Defer Execution

Schedules actuator execution for a future time. Supports relative delays, absolute times, cron expressions, and batching.

@schedule: {
  delay: "5m",                       // Relative delay
  at: "2026-02-01T00:00:00Z",       // Absolute time
  cron: "0 0 * * *",                // Recurring (daily at midnight)
  batch: true,
  batch_window: "1h",
  max_batch_size: 100,
  then: { @agent: { ... } }
}

@message — Inter-Agent Communication

Sends messages between agents via named channels, supporting both fire-and-forget and request-response patterns.

@message: {
  to: "AgentAtom WHERE 'ops_team' IN tags",
  channel: "security-alerts",
  message: "New high-confidence observation: {{observation.summary}}",
  correlation_id: "$trace_id",
  priority: "high",
  await_response: true,
  timeout: "5m"
}

@trigger — Chain to Another Trigger

Chains execution to another TriggerAtom, passing context forward. Enables composable trigger pipelines.

@trigger: {
  trigger_id: "secondary_validation_trigger",
  context: {
    source_observation: "$atom_id",
    proposed_constraint: "{{constraint_proposal}}"
  }
}

5. Actuator Chaining

Sequential Execution

Actuators execute in sequence by default. Use THEN for explicit ordering:

ACTUATE {
  @agent: { ... }           // 1. Agent proposes
  THEN
  @system: { ... }          // 2. System validates
  THEN
  @human: { ... }           // 3. Human approves
  THEN
  @system: { ... }          // 4. System creates
}

Parallel Execution

Use | for concurrent actuators:

ACTUATE {
  @agent: { id: "scout_a" } | @agent: { id: "scout_b" } | @agent: { id: "scout_c" }
  THEN
  @agent: { id: "synthesizer" }
}

Conditional Branching

Use IF/ELSE blocks to branch based on prior results:

ACTUATE {
  @agent: { ... }
  THEN
  IF "{{result.confidence}} >= 0.9" {
    @system: { operation: "create", ... }
  } ELSE {
    @message: { to: "human_reviewer", ... }
  }
}

6. Trigger Lifecycle

Triggers follow a six-stage lifecycle from registration through recording:

StageDescriptionMechanism
RegistrationTrigger created via DGP mutationcreateTrigger mutation → TriggerAtom in graph
LoadingEngine loads enabled triggers at startupIndexed by watched atom type, sorted by priority
WatchingGateway emits events on every atom mutationNATS: adamas.atoms.<AtomType>.created|updated|deleted
MatchingFind triggers watching this atom typeCheck debounce, rate limits, evaluate condition predicates
FiringBuild context and execute actuator chainWITH queries → context → actuator execution → context update
RecordingCreate TriggerFireAtom for audit trailCaptures triggering atom, context snapshot, results, status

Every trigger fire creates a TriggerFireAtom recording the triggering atom, a snapshot of the context at fire time, every actuator executed with its result and duration, and the overall outcome status (success, partial, or failed).

7. Built-in Triggers

Flywheel: Observation → Constraint

When observations reach high confidence and recurrence, automatically propose them as formal constraints:

@trigger ObservationAtom
  WHEN confidence >= 0.9
   AND 'limitation' IN tags
   AND occurrence_count >= 3
  ACTUATE {
    @agent: {
      query: "AgentAtom WHERE 'constraint_proposer' IN tags",
      prompt: "Propose a constraint based on: {{observation.description}}",
      tier: "cheap"
    }
    THEN
    @system: {
      operation: "create",
      atom_type: "ConstraintAtom",
      data: { name: "{{agent_result.proposed_name}}", enforcement: "advisory" }
    }
  }

Flywheel: Constraint → Router Update

When constraints are validated, update the routing engine to reflect new knowledge:

@trigger ConstraintAtom
  WHEN status = 'validated' AND type = 'model_limitation'
  WITH {
    affected_model: "MATCH (c {id: $atom_id})-[:ABOUT]->(m:ModelAtom) RETURN m"
  }
  ACTUATE {
    @system: {
      operation: "update",
      target: "RouterAtom WHERE DEFAULT_MODEL->ModelAtom.id = '{{affected_model.id}}'",
      data: { escalation_rules: "{{escalation_rules}} + [...]" }
    }
    THEN
    @message: {
      channel: "ops-notifications",
      message: "Router updated: {{affected_model.name}} will now escalate"
    }
  }

Security: High-Severity Alert

Critical security observations trigger parallel notification and incident response:

@trigger ObservationAtom
  WHEN type = 'security' AND severity = 'critical'
  ACTUATE {
    @message: {
      to: "AgentAtom WHERE 'security_team' IN tags",
      channel: "security-alerts",
      priority: "high"
    }
    |
    @agent: {
      id: "agent_incident_responder",
      tier: "expensive",
      thinking_budget: 32000
    }
  }

Quality: Failed Execution Analysis

After repeated task failures, trigger root cause analysis with optional task disablement:

@trigger ExecutionAtom
  WHEN success = false AND retry_count >= 3
  WITH {
    recent_failures: "MATCH (e:ExecutionAtom) WHERE e.success = false ... RETURN count(e)",
    task_def: "MATCH (e {id: $atom_id})-[:EXECUTION_OF]->(t:TaskAtom) RETURN t"
  }
  ACTUATE {
    IF "{{recent_failures.count}} > 5" {
      @agent: { query: "AgentAtom WHERE 'failure_analyst' IN tags", tier: "expensive" }
      THEN
      @human: {
        condition: "{{agent_result.recommended_action}} = 'disable_task'",
        prompt: "Analyst recommends disabling task. Approve?",
        timeout: "1h", fallback: "defer"
      }
    } ELSE {
      @message: { channel: "task-failures", message: "Task failed after 3 retries" }
    }
  }

8. CLI Tools

The adamas-triggers CLI manages the full trigger lifecycle:

# List triggers
adamas-triggers list
adamas-triggers list --enabled
adamas-triggers list --watching ObservationAtom

# Show details
adamas-triggers show <trigger_id>

# Enable / disable
adamas-triggers enable <trigger_id>
adamas-triggers disable <trigger_id>

# Dry-run test
adamas-triggers test <trigger_id> --atom '{"confidence": 0.95, "tags": ["limitation"]}'

# Fire history
adamas-triggers history <trigger_id>
adamas-triggers history <trigger_id> --since 24h --status failed

# Create / validate
adamas-triggers create trigger.ttl
adamas-triggers validate trigger.ttl

Example dry-run output:

$ adamas-triggers test promote-observation --atom '{"confidence": 0.95, "tags": ["limitation"]}'

✓ Trigger: promote-observation (enabled)
✓ Condition: MATCHES
  - confidence >= 0.9: 0.95 >= 0.9 ✓
  - 'limitation' IN tags: true ✓

Actuator chain (dry run):
1. @agent: constraint_proposer — Would execute with prompt
2. @system: create ConstraintAtom — Would create from agent result

⚠ Note: Dry run — no actuators were executed

9. Monitoring & Observability

TTL exposes Prometheus-style metrics for operational visibility:

# Trigger fires
turn_trigger_fires_total{trigger_id, status}

# Actuator executions
turn_actuator_executions_total{trigger_id, actuator_type, status}
turn_actuator_duration_ms{trigger_id, actuator_type}

# Rate limiting
turn_trigger_debounced_total{trigger_id}
turn_trigger_rate_limited_total{trigger_id}

TriggerFireAtoms link to SpanAtoms for distributed tracing:

MATCH (fire:TriggerFireAtom)-[:TRACED_BY]->(span:SpanAtom)
WHERE fire.trigger_id = $trigger_id
RETURN fire, span
ORDER BY fire.fired_at DESC
LIMIT 100

10. Security Considerations

Privilege Escalation Prevention

Triggers run with the privileges of the trigger author, not the triggering atom's author. The TriggerEngine validates that the author has permission to invoke the specified agents and mutate the target atom types before the trigger is registered.

Trigger Auditing

All trigger fires are recorded as AuditAtoms capturing the event type, actor (trigger ID), target (atom type and ID), action taken, outcome status, and full trace ID. This provides a complete audit trail for compliance and debugging.