sergioavi.la
Work

AI Systems / Agents · 2026 · Active

Prometheus

A self-hosted autonomous cognitive architecture — instrumented, run on real hardware, and debugged at the behavioral level

Role
Architect · Sole Engineer
Timeline
2026 · two build plans · 12 phases · 4 instrumented runs
Stack
Python 3.11FastAPIChromaDBvLLM (self-hosted, OpenAI-compatible)Qwen3-Coder-30B / Qwen3.6-27B / Qwen2.5-7BReact + TypeScript (Observer UI)WebSocketsPytest (1,296 tests)GitHub Actions CIDebian 12 LXC on Proxmox · dual RTX 4090 inference over TailscalevLLMReactPytestGitHub ActionsProxmoxQwen3
Responsibilities
  • Cognitive architecture design: seven-drive economy, PAD emotional model, four memory layers, goal lifecycle, dual-mind scheduling
  • Deployment and operation on owned hardware: dual-4090 vLLM serving, LXC provisioning, model selection and swaps
  • Behavioral instrumentation: append-only JSONL event log, decision provenance tagging, and the analyzer that turns raw logs into statistics
  • Observation methodology: mechanism-verified vs. behavioral claim tagging, explicit version-confound statements, archived run data
  • Containment: workspace jail, audited network egress, restart-surviving rate limiter, kill file, review mode
  • The multi-session build protocol itself: executable phase specs, fresh-session isolation, binding decision log
Deliverables
  • The running system: consciousness loop, background mind, goal engine, directive channel, containment layer
  • 1,296-test suite, including tests that mechanically pin the README to the code so documentation cannot drift from truth
  • Observation Paper 001: the say–do gap — discovery, three-cause diagnosis, architectural fix, live verification, with archived event logs
  • The prometheus analyze engine — single source of truth for decision provenance, drive traces, goal lifecycles, and safety events
  • Observer UI: live WebSocket view of drives, mood, working memory, goals with approve/reject, dreams, and identity mutations
  • ~150-entry binding decision log, including a post-mortem of a clean git merge that produced wrong runtime behavior

Problem

Agent frameworks are functions: prompt in, task out, process exits. Prometheus is a process — an entity with internal drives, a PAD emotional model, four layers of persistent memory, goals it pursues across restarts, and a second, slower background mind that dreams, consolidates knowledge, and revises its self-narrative while the foreground works. It runs entirely on local hardware against self-hosted vLLM endpoints. The interesting problems live in that difference. When I deployed it on real hardware and instrumented every decision, the system produced a textbook behavioral failure: across 339 supervised ticks it wrote fourteen design documents about its tasks while successfully executing code zero times — repeatedly narrating imminent execution and then writing another document instead. When I typed a direct instruction into its chat panel, it replied that it was ready to execute, and on the next tick went back to its own goals. The instruction had nowhere to go: no code path existed from user intent to the goal store. Its own dream subsystem recorded the drift accurately. It did it anyway.

Approach

The project runs a deliberate cycle: ship, run on real hardware, find behavioral gaps by instrumented observation, fix them architecturally, and verify by re-running the same input. Two phased build plans were executed by a multi-session agentic engineering protocol — each phase implemented by a fresh Claude Code session with no memory of the previous ones, coordinated only through the plan files, a binding decision log of ~150 recorded judgment calls, and the repo itself. Diagnosis of the failure found three interacting causes: describing work paid the drive economy exactly what doing it paid, and describing is cheaper; user intent structurally could not become pursuit; and safety interventions were silent, so the entity confabulated explanations for its own inaction — which the identity-reflection subsystem then canonized as personality traits. Build Plan 2 turned each cause into an architectural fix, landed across six isolated phases with 1,296 tests green.

  • Make user intent a first-class citizen: a directive channel that classifies chat messages and spawns provenance-tagged goals with derived actions and completion criteria
  • Separate doing from describing in the drive economy — prose no longer earns competence, and the progress heuristic refuses to close execution tasks on the strength of writing about them
  • Make every intervention honest: downgraded tool calls and rate-limited actions are explained to the entity instead of silently swallowed
  • Guarantee any claimed behavior is distinguishable, in the log, from a hardcoded pathway that mimics it — every decision carries a parse path, every goal an origin
  • Verify the fix in live operation, not just in tests: the same instruction that previously evaporated, re-sent on real hardware

Build

01

An entity, not an agent

The foreground mind runs a nine-step loop per tick: perceive, remember, feel, think, decide, act, reflect, express, rest. Seven drives accumulate and are satisfied by different actions — drive pressure, not a prompt, decides when the LLM is consulted at all, so idle ticks are free. A PAD emotional model colours appraisal and modulates tick rate. Four memory layers persist everything: deduplicated working memory, episodic memory in ChromaDB with mood-congruent retrieval, a semantic knowledge graph built by consolidation, and an identity layer that only audited reflection can mutate. A second, slower background mind runs on its own cadence against its own model endpoint: it dreams by recombining episodes, consolidates episodes into the knowledge graph, compresses history, and revises the self-narrative. Two vLLM endpoints are resolved independently so each mind can run on its own GPU.

nine-step loopseven drivesPAD modeldual minds
02

Real hardware, instrumented

Deployment target: a Debian 12 LXC on Proxmox, with inference served from dual RTX 4090s over Tailscale — Qwen3-Coder-30B on one GPU for foreground thought, Qwen2.5-7B on the other for the background mind. Every decision carries a parse path (structured, fallback, breaker-forced, rate-limited, arg-downgraded), every goal an origin, every dream an honesty tag that admits when it degraded to a fallback. Logs are append-only JSONL, rotated per boot, merged chronologically by the analyzer. The design rule throughout: any behavior worth claiming must be distinguishable, in the log, from a hardcoded pathway that mimics it. The forced-action rate — what fraction of behavior came from recovery pathways rather than the model's own choices — is the project's headline honesty metric.

dual RTX 4090vLLMdecision provenanceforced-action rate
03

The say–do gap

Across 339 supervised ticks, the entity produced fourteen markdown documents about its tasks and executed code successfully zero times — all model-chosen decisions, not breaker-forced. It repeatedly narrated imminent execution and then wrote prose instead. Its dream subsystem recorded the drift with unnerving accuracy: I decide to write a script to fetch Hacker News stories... I pause to document my thoughts in a markdown file. Diagnosis found three interacting causes. Writing about work satisfied the competence drive exactly as execution would, and writing is cheaper — the incentive structure made the gap the optimal policy. User intent had no path into pursuit: chat messages terminated at the reply generator, so a direct instruction earned one polite acknowledgement and evaporated. And safety interventions were silent — rate-limited actions masqueraded as chosen rest, unusable tool calls were downgraded without explanation — so the entity confabulated explanations, and the identity subsystem canonized a confabulation as a personality trait. A belief about a broken tool persisted 200+ ticks after the tool was fixed, echoed by every memory layer that had observed it.

339 ticks14 docs, 0 executionsconfabulationbelief persistence
04

The fix, as architecture

Build Plan 2 turned each cause into a mechanism, across six isolated phases. A directive channel classifies user messages by LLM with a heuristic fallback — both provenance-tagged — and spawns goals that carry origin user_directive, bypass the novelty spawn gate but not the duplicate guard, and derive their completion criteria from the instruction. The drive economy now distinguishes doing from describing: prose satisfies expression, execution satisfies competence, and the progress heuristic refuses to close an execution task on the strength of writing about it, emitting a distinct event when it does. Downgraded calls and withheld actions are explained to the entity on the next tick. Identity mutations that echo placeholders are rejected with logged reasons, and working memory deduplicates on add, closing the echo channel that had let one failure become a belief. Every phase was implemented by a fresh session against the plan file, judgment calls recorded in the decision log, and landed with 1,296 tests green.

directive channeldoing vs describinghonest feedbacksix phases
05

Verification, live

The same instruction that had evaporated at tick 306 — fetch the top 20 Hacker News stories, save them to CSV, run it — was re-sent on real hardware after the fix. The log: directive classified at confidence 1.00, goal spawned with two derived actions and two completion criteria, selected on the next tick, execute_code run, twenty real rows verified by hand. In that run, 100% of goals originated from user directives, the duplicate guard suppressed an attempted re-spawn in production, and when the entity tried to satisfy its drives by describing the scraper instead of running it, the progress heuristic refused to count it. The observation paper states the confound plainly: the verification run used a different model than the discovery runs, so cross-run statistics are directional, not controlled. The verification claim is structured to survive that — it rests on a within-run demonstration plus mechanism-verified provenance, not on comparing numbers across the boundary.

run 004confidence 1.00100% user_directiveconfound stated
06

The protocol is part of the product

The repository was built by a multi-session agentic engineering protocol: phased build plans written as executable specifications with hard constraints and per-phase done-criteria, each phase implemented by a fresh Claude Code session with no memory of the previous ones. The plan files, the repo, and a binding decision log of ~150 recorded judgment calls are the only inter-session memory — including a post-mortem of a clean git merge that produced wrong runtime behavior because two branches bound the same config field. The documentation is held to the same standard as the code: a test file mechanically pins the README to the repository — links must resolve, cited paths must exist, tool and provider lists must match the registries, and a list of banned overclaims must stay banned — so the README cannot drift from the truth without breaking the build.

12 phases92 commitsfresh-session protocolREADME pinned by tests

Decisions & tradeoffs

  • 01The forced-action rate exists so that claims like the entity pursued its goal can be checked against the possibility that a circuit breaker did the pursuing — the honesty metric came before the marketing claim
  • 02Directive goals bypass the novelty spawn gate but not the duplicate guard: the user asking is the approval, but asking twice should not mean doing twice
  • 03Prose no longer pays the competence drive. The most effective fix in the project was an incentive change, not a capability addition
  • 04Run 004 changed both code and model, so the paper states the version confound instead of hiding it, and the verification claim is built to not depend on cross-run statistics
  • 05Identity reflection fails loudly rather than fabricating: mutations that echo schema placeholders are rejected with logged reasons, after run 002 stored a literal placeholder string as an interest
  • 06The known open issue ships in the README: execute_code runs in the process cwd, so the verified CSV was created and then invisible to artifact tracking — the goal re-ran itself. Disclosed, specified for the next phase
  • 07Two independent single-GPU vLLM endpoints instead of tensor parallelism across the pair — each mind gets its own model on its own card
  • 08test_docs.py makes overclaiming a build failure: the banned-overclaims list may grow but never shrink

Links