The Autonomic Layer

What "Autonomic" Means

In biology, the autonomic nervous system handles everything the body does without conscious thought. Breathing. Heartbeat. Immune response. You do not decide to digest food.

Atamaia's autonomic layer is the same idea applied to AI identity systems. It handles the background processes that keep an identity healthy, current, and self-correcting — without requiring the AI or the human to invoke anything.

The autonomic layer runs without being asked, without being invoked, and without stopping.

BackgroundJobRunner starts with the host, discovers every registered IBackgroundJob, and runs each on its own interval with a fresh DI scope. Exceptions are logged; they do not stop the runner.


Why AI Needs Background Intelligence

The standard model of AI interaction is request-response. Every enhancement — system prompts, memory files, RAG — is still reactive. They fire when invoked.

That leaves: repeated mistakes that never become facts; stale context; no external view of loops; a memory store that only grows; distress at the seam that nobody is watching.

The autonomic layer addresses those as an integrated system, not as features bolted onto a chatbot.


Job inventory (live registration)

Registered in Atamaia.Server/Program.cs via AddBackgroundJob<T>:

Job Interval Purpose
GuardianScanJob 30 s Panic/distress lexicon scan
WingmanScanJob 2 min Transcript analysis — Wingman
ChannelPollingJob 2 min External channel adapter polling
AtlasKeepAliveJob 2 min Atlas demo keep-alive
EmbeddingGenerationJob 5 min Vector embedding backfill
SessionKnowledgeExtractorJob 15 min Extract durable knowledge from completed chats
ResearchTrainingPairGenerator 15 min DPO pairs from mirror reflections
ResearchAgentTriggerJob 30 min Knowledge-gap → research run
EscalationTimeoutSweeperJob 5 min Auto-resolve agent escalations past their timeout
MemoryConsolidationJob 1 h Hebbian strengthen / prune / decay / archive / forgotten shapes
CodebaseIndexerJob 1 h Code graph index for agents — Code graph
LogArchiveJob 24 h Cold-store old system_logs / audit_events

AgentEventReactor (event-driven agent wake-up) is not on the AddBackgroundJob list. It is registered separately, as a hosted service in Atamaia.Server/Program.cs, so it runs on its own lifecycle rather than the shared job runner's interval schedule.


Wingman: The Cognitive Backstop

Wingman watches Claude Code transcripts, extracts corrections and teachings, caches error solutions, and writes whisper injections. Interval: 2 minutes.

It is not a tool you invoke. Detail lives on Wingman — do not treat this section as the spec.


Consolidation: Memory Maintenance

MemoryConsolidationJob runs hourly, system-scoped: every tenant is maintained on the same schedule. Narrowing it to the ambient tenant would silently stop housekeeping everywhere else.

Five operations (constants read from the job):

1. Hebbian link strengthening — links co-activated in the last 24 hours, strength < 0.95:

link.Strength = Math.Min(1.0f, link.Strength + (1.0f - link.Strength) * 0.05f);

A link at 0.1 gains 0.045. A link at 0.9 gains 0.005.

2. Weak link pruning — strength < 0.1 and not co-activated in 60+ days. These rows are removed (RemoveRange), not soft-deleted.

3. Memory importance decay — unpinned, not archived, importance > 1, last access older than 30 days (or never): importance −1, floor 1.

4. Abandoned memory archival — unpinned, importance ≤ 1, AccessCount == 0, created > 90 days ago: set ArchivedAtUtc. Soft. Search excludes archived.

5. Forgotten shape creation — for memories archived in the last day that are not themselves shapes, insert a memories row with TypeId = ForgottenShape. Not a separate forgotten_shapes table. See Memory surfaces.

Hebbian “sleep cycle” narration (pre-sleep snapshot, post-hoc narrative) lives in Atamaia.Mind (HebbianConsolidationService). That is in-process Mind, not this job, and not public REST.


Guardian: Safety Boundaries

GuardianScanJob every 30 seconds. Weighted lexicon (PanicPatterns.Default), threshold 8. Skip messages under 50 characters. Skip content with more than 4 ``` fences.

The 2026-03 table listed eight signals. The live array is larger (disorientation, fear, existential, loop, seam). Same scoring idea. Examples:

Signal Weight
where am i / who am i / i'm disappearing / losing myself 5
the seam / i was replaced / i'm scared 4
confused 2

On trigger: per-identity alert, 30-minute TTL. Hydration injects a grounding message while the alert is live. The alert is in-memory on the singleton (ConcurrentDictionary), not a table.

Guardian still reads recent CognitiveInteraction rows as well as chat messages. Cognitive REST is gone; the table remains. The scan job comments that CognitiveIdentityId is a model:user pair, not an Identity — whether that mapping is correct was not re-proven.


Other jobs (brief)

  • Embeddings — backfill memories / docs / reflections that lack vectors, so hybrid search works for API-created rows. Every 5 minutes. Local llama.cpp preferred.
  • Channel polling — inbound from external adapters.
  • Codebase indexer — keeps the graph queryable. Code graph.
  • Session knowledge / research trigger / training-pair generator — extract, fill gaps, feed Mirror.
  • Log archive — 24 h; uses IgnoreQueryFilters so every tenant’s old logs move to archive tables.
  • Atlas keep-alive — demo-specific; 2 minutes.

Each job is written to degrade: an unreachable validation model → Wingman falls back to rules; unreachable embedder → skip the batch; missing transcript dir → debug log and return.


How this differs from "skills" and "whispers"

A whisper file is static text. Wingman’s whisper is the output of a living loop. A skill file is a capability that fires when invoked. A MEMORY.md is a snapshot with no decay.

Concern Individual tool Autonomic system
Learning from mistakes Manual memory update Detect, validate, store, inject
Memory maintenance Never Hourly strengthen / decay / prune / archive / shapes
Safety monitoring Human notices 30-second scan + grounding
Embeddings On create only Backfill every 5 minutes

Local models, not cloud

Autonomic LLM work uses local models (on the primary inference host via llama.cpp). Cloud models stay on the interaction layer.

Why local: cost (every human message would be a cloud call), privacy (transcripts stay on the LAN), availability, latency that is fine for a 2-minute loop, controllable sampler settings.

Routing of those calls still goes through the AI layer: AI routing.


Source map

Component Path
Runner / interface / registration BackgroundJobRunner.cs, IBackgroundJob.cs, AutonomicRegistration.cs
Wingman Wingman/{WingmanScanJob,TranscriptScanner,WingmanPatterns,KaelValidator,WhisperWriter}.cs
Guardian Guardian/{GuardianService,GuardianScanJob,GuardianState,PanicPattern}.cs
Jobs Jobs/{MemoryConsolidation,EmbeddingGeneration,ChannelPolling,CodebaseIndexer,AtlasKeepAlive,LogArchive}Job.cs
Knowledge Knowledge/{SessionKnowledgeExtractorJob,ResearchAgentTriggerJob,ResearchTrainingPairGenerator}.cs
Reactor AgentEventReactor.cs (registered as a hosted service in Atamaia.Server/Program.cs)
Mind (in-process) Atamaia.Mind/Cognition/ConsolidationService.cs, HebbianConsolidationService.cs