anima-core 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.reek.yml +23 -26
- data/README.md +118 -104
- data/agents/thoughts-analyzer.md +12 -7
- data/anima-core.gemspec +1 -0
- data/app/channels/session_channel.rb +38 -58
- data/app/decorators/agent_message_decorator.rb +7 -2
- data/app/decorators/message_decorator.rb +31 -100
- data/app/decorators/pending_from_melete_decorator.rb +36 -0
- data/app/decorators/pending_from_melete_goal_decorator.rb +13 -0
- data/app/decorators/pending_from_melete_skill_decorator.rb +19 -0
- data/app/decorators/pending_from_melete_workflow_decorator.rb +13 -0
- data/app/decorators/pending_from_mneme_decorator.rb +44 -0
- data/app/decorators/pending_message_decorator.rb +94 -0
- data/app/decorators/pending_subagent_decorator.rb +46 -0
- data/app/decorators/pending_tool_response_decorator.rb +51 -0
- data/app/decorators/pending_user_message_decorator.rb +22 -0
- data/app/decorators/system_message_decorator.rb +5 -0
- data/app/decorators/tool_call_decorator.rb +16 -5
- data/app/decorators/tool_response_decorator.rb +2 -2
- data/app/decorators/user_message_decorator.rb +7 -2
- data/app/jobs/count_tokens_job.rb +23 -0
- data/app/jobs/drain_job.rb +169 -0
- data/app/jobs/melete_enrichment_job/goal_change_listener.rb +52 -0
- data/app/jobs/melete_enrichment_job.rb +48 -0
- data/app/jobs/mneme_enrichment_job.rb +46 -0
- data/app/jobs/tool_execution_job.rb +87 -0
- data/app/models/concerns/token_estimation.rb +54 -0
- data/app/models/goal.rb +23 -11
- data/app/models/message.rb +46 -48
- data/app/models/pending_message.rb +407 -12
- data/app/models/pinned_message.rb +8 -3
- data/app/models/session.rb +660 -566
- data/app/models/snapshot.rb +11 -21
- data/bin/inspect-cassette +157 -0
- data/bin/release +212 -0
- data/bin/with-llms +20 -0
- data/config/application.rb +1 -0
- data/config/database.yml +1 -0
- data/config/initializers/event_subscribers.rb +71 -4
- data/config/initializers/inflections.rb +3 -1
- data/db/cable_structure.sql +9 -0
- data/db/migrate/20260330120000_add_source_to_pending_messages.rb +8 -0
- data/db/migrate/20260401180000_add_api_metrics_to_messages.rb +7 -0
- data/db/migrate/20260401210935_remove_recalled_message_ids_from_sessions.rb +5 -0
- data/db/migrate/20260403080031_add_initial_cwd_to_sessions.rb +5 -0
- data/db/migrate/20260407170803_remove_viewport_message_ids_from_sessions.rb +5 -0
- data/db/migrate/20260407180400_remove_mneme_snapshot_pointer_columns_from_sessions.rb +6 -0
- data/db/migrate/20260411120553_add_token_count_to_pinned_messages.rb +5 -0
- data/db/migrate/20260411172926_remove_active_skills_and_workflow_from_sessions.rb +6 -0
- data/db/migrate/20260412110625_replace_processing_with_aasm_state.rb +6 -0
- data/db/migrate/20260418150323_add_kind_and_message_type_to_pending_messages.rb +6 -0
- data/db/migrate/20260419120000_add_drain_fields_to_pending_messages.rb +7 -0
- data/db/migrate/20260419130000_drop_pending_messages_kind_default.rb +5 -0
- data/db/migrate/20260419140000_add_drain_indexes_to_pending_messages.rb +8 -0
- data/db/migrate/20260420100000_add_hud_visibility_to_sessions.rb +15 -0
- data/db/queue_structure.sql +61 -0
- data/db/structure.sql +133 -0
- data/lib/agents/registry.rb +1 -1
- data/lib/anima/cli.rb +41 -13
- data/lib/anima/installer.rb +13 -0
- data/lib/anima/settings.rb +16 -36
- data/lib/anima/version.rb +1 -1
- data/lib/events/authentication_required.rb +24 -0
- data/lib/events/bounce_back.rb +4 -4
- data/lib/events/eviction_completed.rb +28 -0
- data/lib/events/goal_created.rb +28 -0
- data/lib/events/goal_updated.rb +32 -0
- data/lib/events/llm_responded.rb +35 -0
- data/lib/events/message_created.rb +27 -0
- data/lib/events/message_updated.rb +25 -0
- data/lib/events/session_state_changed.rb +30 -0
- data/lib/events/skill_activated.rb +28 -0
- data/lib/events/start_melete.rb +36 -0
- data/lib/events/start_mneme.rb +33 -0
- data/lib/events/start_processing.rb +32 -0
- data/lib/events/subagent_evicted.rb +31 -0
- data/lib/events/subscribers/active_state_broadcaster.rb +27 -0
- data/lib/events/subscribers/authentication_broadcaster.rb +34 -0
- data/lib/events/subscribers/drain_kickoff.rb +20 -0
- data/lib/events/subscribers/eviction_broadcaster.rb +26 -0
- data/lib/events/subscribers/llm_response_handler.rb +111 -0
- data/lib/events/subscribers/melete_kickoff.rb +24 -0
- data/lib/events/subscribers/message_broadcaster.rb +34 -0
- data/lib/events/subscribers/mneme_kickoff.rb +24 -0
- data/lib/events/subscribers/mneme_scheduler.rb +21 -0
- data/lib/events/subscribers/persister.rb +8 -9
- data/lib/events/subscribers/session_state_broadcaster.rb +33 -0
- data/lib/events/subscribers/subagent_message_router.rb +28 -34
- data/lib/events/subscribers/subagent_visibility_broadcaster.rb +33 -0
- data/lib/events/subscribers/tool_response_creator.rb +33 -0
- data/lib/events/subscribers/transient_broadcaster.rb +1 -1
- data/lib/events/tool_executed.rb +34 -0
- data/lib/events/workflow_activated.rb +27 -0
- data/lib/llm/client.rb +46 -199
- data/lib/mcp/client_manager.rb +41 -46
- data/lib/mcp/stdio_transport.rb +9 -5
- data/lib/{analytical_brain → melete}/runner.rb +73 -68
- data/lib/{analytical_brain → melete}/tools/activate_skill.rb +3 -3
- data/lib/{analytical_brain → melete}/tools/assign_nickname.rb +3 -3
- data/lib/{analytical_brain → melete}/tools/everything_is_ready.rb +2 -2
- data/lib/{analytical_brain → melete}/tools/finish_goal.rb +6 -3
- data/lib/melete/tools/goal_messaging.rb +29 -0
- data/lib/{analytical_brain → melete}/tools/read_workflow.rb +4 -4
- data/lib/{analytical_brain → melete}/tools/rename_session.rb +3 -3
- data/lib/{analytical_brain → melete}/tools/set_goal.rb +6 -2
- data/lib/{analytical_brain → melete}/tools/update_goal.rb +9 -5
- data/lib/{analytical_brain.rb → melete.rb} +6 -3
- data/lib/mneme/base_runner.rb +121 -0
- data/lib/mneme/l2_runner.rb +14 -20
- data/lib/mneme/recall_runner.rb +132 -0
- data/lib/mneme/runner.rb +123 -165
- data/lib/mneme/search.rb +104 -62
- data/lib/mneme/tools/nothing_to_surface.rb +25 -0
- data/lib/mneme/tools/save_snapshot.rb +2 -10
- data/lib/mneme/tools/surface_memory.rb +89 -0
- data/lib/mneme.rb +11 -5
- data/lib/providers/anthropic.rb +112 -7
- data/lib/shell_session.rb +290 -432
- data/lib/skills/definition.rb +2 -2
- data/lib/skills/registry.rb +1 -1
- data/lib/tools/base.rb +16 -1
- data/lib/tools/bash.rb +25 -55
- data/lib/tools/edit.rb +2 -0
- data/lib/tools/mark_goal_completed.rb +4 -5
- data/lib/tools/read.rb +2 -0
- data/lib/tools/registry.rb +85 -4
- data/lib/tools/response_truncator.rb +1 -1
- data/lib/tools/{recall.rb → search_messages.rb} +19 -21
- data/lib/tools/spawn_specialist.rb +22 -14
- data/lib/tools/spawn_subagent.rb +30 -20
- data/lib/tools/subagent_prompts.rb +17 -19
- data/lib/tools/think.rb +1 -1
- data/lib/tools/{remember.rb → view_messages.rb} +10 -10
- data/lib/tools/write.rb +2 -0
- data/lib/tui/app.rb +393 -149
- data/lib/tui/braille_spinner.rb +7 -7
- data/lib/tui/cable_client.rb +9 -16
- data/lib/tui/decorators/base_decorator.rb +47 -6
- data/lib/tui/decorators/bash_decorator.rb +1 -1
- data/lib/tui/decorators/edit_decorator.rb +4 -2
- data/lib/tui/decorators/read_decorator.rb +4 -2
- data/lib/tui/decorators/think_decorator.rb +2 -2
- data/lib/tui/decorators/web_get_decorator.rb +1 -1
- data/lib/tui/decorators/write_decorator.rb +4 -2
- data/lib/tui/flash.rb +19 -14
- data/lib/tui/formatting.rb +20 -9
- data/lib/tui/input_buffer.rb +6 -6
- data/lib/tui/message_store.rb +165 -28
- data/lib/tui/performance_logger.rb +2 -3
- data/lib/tui/screens/chat.rb +149 -79
- data/lib/tui/settings.rb +93 -0
- data/lib/workflows/definition.rb +3 -3
- data/lib/workflows/registry.rb +1 -1
- data/skills/github.md +38 -0
- data/templates/config.toml +16 -32
- data/templates/tui.toml +209 -0
- data/workflows/review_pr.md +18 -14
- metadata +98 -29
- data/app/jobs/agent_request_job.rb +0 -199
- data/app/jobs/analytical_brain_job.rb +0 -33
- data/app/jobs/count_message_tokens_job.rb +0 -39
- data/app/jobs/passive_recall_job.rb +0 -29
- data/app/models/concerns/message/broadcasting.rb +0 -85
- data/config/initializers/fts5_schema_dump.rb +0 -21
- data/lib/agent_loop.rb +0 -186
- data/lib/analytical_brain/tools/deactivate_skill.rb +0 -39
- data/lib/analytical_brain/tools/deactivate_workflow.rb +0 -34
- data/lib/environment_probe.rb +0 -232
- data/lib/events/agent_message.rb +0 -11
- data/lib/events/subscribers/message_collector.rb +0 -64
- data/lib/events/tool_call.rb +0 -31
- data/lib/events/tool_response.rb +0 -33
- data/lib/mneme/compressed_viewport.rb +0 -200
- data/lib/mneme/passive_recall.rb +0 -69
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9fb5f4e6879e02892c861885896a154798a14e5eefa12ed0decaff968a085f5d
|
|
4
|
+
data.tar.gz: c28b8e1c2aed9cea3a3f9a6735f289961c1727562684b19960580b293bfd40cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4cb148defa8d0b81ecb1559966f483137ebc10f24ee47c7ac4cc27d0e17332cf2232d45507e4abe7c67b4bdc364c7fd5f7ccd2ff70dac29fe43b2f21a277b1f4
|
|
7
|
+
data.tar.gz: 18227bfc5e3be5883f87c07f5215c10d97bb9565d3c41fb23e2799ce8624f83b9e1a15ad30c772c58119664d8d0adcfc6a68e5e456a17dc04e61f55a0e24e0c9
|
data/.reek.yml
CHANGED
|
@@ -13,43 +13,43 @@ detectors:
|
|
|
13
13
|
NilCheck:
|
|
14
14
|
exclude:
|
|
15
15
|
- "Anima::Settings#get"
|
|
16
|
+
- "TUI::Settings#get"
|
|
16
17
|
# Rescue blocks naturally reference the error object more than self.
|
|
17
|
-
#
|
|
18
|
-
# Brain transcript builds from event collection — the method's entire purpose.
|
|
18
|
+
# Melete transcript builds from event collection — the method's entire purpose.
|
|
19
19
|
# ConfigMigrator text processing methods naturally reference local line arrays.
|
|
20
20
|
# ToolDecorator subclasses operate on the tool result — that's the pattern.
|
|
21
21
|
# Tool rescue blocks naturally reference the error object.
|
|
22
22
|
FeatureEnvy:
|
|
23
23
|
exclude:
|
|
24
|
-
- "
|
|
25
|
-
- "EnvironmentProbe"
|
|
26
|
-
- "AnalyticalBrain::Runner#build_messages"
|
|
24
|
+
- "Melete::Runner#build_messages"
|
|
27
25
|
- "Anima::ConfigMigrator"
|
|
28
26
|
- "WebGetToolDecorator"
|
|
29
27
|
- "Tools::WebGet#validate_and_fetch"
|
|
30
|
-
#
|
|
31
|
-
- "Tools::
|
|
28
|
+
# ViewMessages renders events from other objects — formatting IS the job.
|
|
29
|
+
- "Tools::ViewMessages"
|
|
32
30
|
# Event subscribers extract payload fields — inherent to the pattern.
|
|
33
31
|
- "Events::Subscribers::SubagentMessageRouter"
|
|
32
|
+
# Query-style predicate operates on the argument by design.
|
|
33
|
+
- "Session#subagent_trace_in_viewport?"
|
|
34
|
+
# Visibility restore operates on the child session — that's the job.
|
|
35
|
+
- "PendingMessage#restore_subagent_hud_visibility!"
|
|
34
36
|
# Spawn tools orchestrate child session creation — references are the job.
|
|
35
37
|
- "Tools::SpawnSubagent#spawn_child"
|
|
36
38
|
- "Tools::SpawnSpecialist#spawn_child"
|
|
37
39
|
- "Tools::SpawnSpecialist#execute"
|
|
38
40
|
# Spawn helpers operate on child session — inherent to the mixin pattern.
|
|
39
|
-
- "Tools::SubagentPrompts#
|
|
41
|
+
- "Tools::SubagentPrompts#assign_nickname_via_melete"
|
|
40
42
|
- "Tools::SubagentPrompts#inject_identity_context"
|
|
41
43
|
# Registry dispatches to tool's threshold method — duck-typing delegation.
|
|
42
44
|
- "Tools::Registry#truncation_threshold"
|
|
43
45
|
# Goal tools operate on goal objects — inherent to the pattern.
|
|
44
|
-
- "
|
|
46
|
+
- "Melete::Tools::UpdateGoal#execute"
|
|
45
47
|
# Validation methods naturally reference the validated value more than self.
|
|
46
|
-
- "
|
|
48
|
+
- "Melete::Tools::AssignNickname#validate"
|
|
47
49
|
# Tool execute methods naturally reference input hash and shell result hash.
|
|
48
50
|
- "Tools::Bash#execute"
|
|
49
51
|
- "Tools::Bash#execute_single"
|
|
50
52
|
- "Tools::Bash#execute_batch"
|
|
51
|
-
# Delivery method orchestrates session, event, and agent_loop — inherent.
|
|
52
|
-
- "AgentRequestJob#deliver_persisted_event"
|
|
53
53
|
# Private helpers don't need instance state to be valid.
|
|
54
54
|
# ActiveJob#perform is always a utility function by design.
|
|
55
55
|
# No-op tools (Think, EverythingIsReady) don't need instance state — by design.
|
|
@@ -59,8 +59,7 @@ detectors:
|
|
|
59
59
|
UtilityFunction:
|
|
60
60
|
public_methods_only: true
|
|
61
61
|
exclude:
|
|
62
|
-
- "
|
|
63
|
-
- "PassiveRecallJob#perform"
|
|
62
|
+
- "MeleteEnrichmentJob#perform"
|
|
64
63
|
- "Tools::Think#execute"
|
|
65
64
|
- "TUI::Formatting"
|
|
66
65
|
- "WebGetToolDecorator#method_missing"
|
|
@@ -68,15 +67,15 @@ detectors:
|
|
|
68
67
|
- "WebGetToolDecorator#text_html"
|
|
69
68
|
# Session model is the core domain object — methods grow naturally.
|
|
70
69
|
# Mcp CLI accumulates subcommand helpers across add/remove/list/secrets.
|
|
71
|
-
#
|
|
72
|
-
#
|
|
70
|
+
# ShellSession probes multiple orthogonal facets (CWD, Git, project files)
|
|
71
|
+
# and manages PTY lifecycle — methods grow with responsibilities.
|
|
73
72
|
TooManyMethods:
|
|
74
73
|
exclude:
|
|
75
74
|
- "Session"
|
|
76
75
|
- "Anima::CLI::Mcp"
|
|
77
|
-
- "
|
|
76
|
+
- "ShellSession"
|
|
78
77
|
# Runner composes system prompt from modular sections — methods grow with responsibilities.
|
|
79
|
-
- "
|
|
78
|
+
- "Melete::Runner"
|
|
80
79
|
# Decorators branch on tool type across 4 render modes — inherent to the pattern.
|
|
81
80
|
# Installer methods each guard idempotency with config_path.exist? — by design.
|
|
82
81
|
RepeatedConditional:
|
|
@@ -84,13 +83,13 @@ detectors:
|
|
|
84
83
|
- "ToolCallDecorator"
|
|
85
84
|
- "Anima::Installer"
|
|
86
85
|
# Runner checks session type to compose responsibilities — the core dispatch.
|
|
87
|
-
- "
|
|
86
|
+
- "Melete::Runner"
|
|
88
87
|
# EventDecorator holds shared rendering constants (icons, markers, dispatch maps).
|
|
89
|
-
#
|
|
88
|
+
# Message holds domain type constants (TYPES, LLM_TYPES, CONVERSATION_TYPES, etc.).
|
|
90
89
|
TooManyConstants:
|
|
91
90
|
exclude:
|
|
92
91
|
- "EventDecorator"
|
|
93
|
-
- "
|
|
92
|
+
- "Message"
|
|
94
93
|
# encode_utf8 is descriptive — the digit triggers a false positive.
|
|
95
94
|
UncommunicativeMethodName:
|
|
96
95
|
exclude:
|
|
@@ -108,16 +107,14 @@ detectors:
|
|
|
108
107
|
exclude:
|
|
109
108
|
- "Tools::WebGet#validate_and_fetch"
|
|
110
109
|
# Remember tool accesses event data for formatting — inherent to rendering.
|
|
111
|
-
- "Tools::
|
|
110
|
+
- "Tools::ViewMessages"
|
|
112
111
|
# Nickname validation checks parent_session for existence then queries — two calls, one guard.
|
|
113
|
-
- "
|
|
114
|
-
# Delivery method references session.id for lookup, BounceBack, and auth broadcast.
|
|
115
|
-
- "AgentRequestJob#deliver_persisted_event"
|
|
112
|
+
- "Melete::Tools::AssignNickname#sibling_nickname_taken?"
|
|
116
113
|
# Method length is enforced by code review, not arbitrary line counts
|
|
117
114
|
# build_sections passes context through to sub-methods — inherent to assembly.
|
|
118
115
|
LongParameterList:
|
|
119
116
|
exclude:
|
|
120
|
-
- "Tools::
|
|
117
|
+
- "Tools::ViewMessages#build_sections"
|
|
121
118
|
# Method length is enforced by code review, not arbitrary line counts
|
|
122
119
|
TooManyStatements:
|
|
123
120
|
enabled: false
|
data/README.md
CHANGED
|
@@ -8,13 +8,13 @@ Every AI agent today is a tool pretending to be a person. One brain doing everyt
|
|
|
8
8
|
|
|
9
9
|
Anima is different. It's built on the premise that if you want an agent — a real one — you need to solve the problems nobody else is solving.
|
|
10
10
|
|
|
11
|
-
**A brain modeled after biology, not chat.** The human brain isn't one process — it's specialized subsystems on a shared signal bus. Anima
|
|
11
|
+
**A brain modeled after biology, not chat.** The human brain isn't one process — it's specialized subsystems on a shared signal bus. Anima mirrors this with a triptych named after the three original Muses: **Aoide** performs (voice, reasoning, tool use), **[Melete](#preparation-as-a-second-brain-melete)** prepares (skills, workflows, goals, naming), **[Mneme](#semantic-memory-mneme)** remembers (summarization, compression, recall). Three processes on the same event bus, each doing one job well. More subsystems are coming.
|
|
12
12
|
|
|
13
|
-
**Context that never degrades.** Other agents fill a static array until the model gets dumb. Anima assembles a fresh viewport over an event bus every iteration. No compaction. No lossy rewriting. Endless sessions. The [dumb zone](https://github.com/humanlayer/advanced-context-engineering-for-coding-agents/blob/main/ace-fca.md) never arrives —
|
|
13
|
+
**Context that never degrades.** Other agents fill a static array until the model gets dumb. Anima assembles a fresh viewport over an event bus every iteration. No compaction. No lossy rewriting. Endless sessions. The [dumb zone](https://github.com/humanlayer/advanced-context-engineering-for-coding-agents/blob/main/ace-fca.md) never arrives — Melete curates what Aoide sees in real time.
|
|
14
14
|
|
|
15
|
-
**Memory that works like memory.** Other systems bolt on memory as an afterthought — filing cabinets the agent has to consciously open mid-task. It never does; the truck is already moving.
|
|
15
|
+
**Memory that works like memory.** Other systems bolt on memory as an afterthought — filing cabinets the agent has to consciously open mid-task. It never does; the truck is already moving. Mneme, the muse of memory, runs as a background process on the event bus. She summarizes what's about to leave the viewport. She compresses short-term into long-term, like biological memory consolidating during sleep. She pins critical moments to active goals so exact instructions survive where summaries would lose nuance. And she recalls — automatically, passively — surfacing relevant older memories right after the soul, right before the present. Aoide doesn't decide to remember. She just remembers.
|
|
16
16
|
|
|
17
|
-
**Sub-agents that
|
|
17
|
+
**Sub-agents that know who they are.** When Anima spawns a sub-agent, it starts clean — identity, task, and nothing else. No inherited conversation history means the sub-agent works on its task, not the parent's trajectory. Context flows through explicit messages, not leaked assistant turns.
|
|
18
18
|
|
|
19
19
|
**A soul the agent writes itself.** Anima's first session is birth. The agent wakes up, explores its world, meets its human, and writes its own identity. Not a personality description in a config file — a living document the agent authors and evolves. Always in context, always its own.
|
|
20
20
|
|
|
@@ -23,20 +23,24 @@ Your agent. Your machine. Your rules. Anima runs locally as a headless Rails 8.1
|
|
|
23
23
|
## Table of Contents
|
|
24
24
|
|
|
25
25
|
- [Architecture](#architecture)
|
|
26
|
+
- [Three Muses](#three-muses)
|
|
27
|
+
- [Installation](#installation)
|
|
28
|
+
- [Distribution Model](#distribution-model)
|
|
29
|
+
- [Authentication Setup](#authentication-setup)
|
|
26
30
|
- [Agent Capabilities](#agent-capabilities)
|
|
27
31
|
- [Tools](#tools)
|
|
28
32
|
- [Sub-Agents](#sub-agents)
|
|
29
33
|
- [Skills](#skills)
|
|
30
34
|
- [Workflows](#workflows)
|
|
31
35
|
- [MCP Integration](#mcp-integration)
|
|
32
|
-
- [Analytical Brain](#analytical-brain)
|
|
33
36
|
- [Configuration](#configuration)
|
|
34
37
|
- [Design](#design)
|
|
35
38
|
- [Three Layers](#three-layers-mirroring-biology)
|
|
36
39
|
- [Event-Driven Design](#event-driven-design)
|
|
37
40
|
- [Context as Viewport](#context-as-viewport-not-tape)
|
|
38
41
|
- [Brain as Microservices](#brain-as-microservices-on-a-shared-event-bus)
|
|
39
|
-
- [
|
|
42
|
+
- [Preparation as a Second Brain (Melete)](#preparation-as-a-second-brain-melete)
|
|
43
|
+
- [Semantic Memory (Mneme)](#semantic-memory-mneme)
|
|
40
44
|
- [TUI HUD & View Modes](#tui-hud--view-modes)
|
|
41
45
|
- [Plugin Architecture](#plugin-architecture-planned)
|
|
42
46
|
- [The Vision](#the-vision)
|
|
@@ -54,63 +58,28 @@ Your agent. Your machine. Your rules. Anima runs locally as a headless Rails 8.1
|
|
|
54
58
|
|
|
55
59
|
## Architecture
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
Anima (Ruby, Rails 8.1 headless)
|
|
59
|
-
│
|
|
60
|
-
│ Implemented:
|
|
61
|
-
├── Nous — main LLM (cortex: thinking, decisions, tool use)
|
|
62
|
-
├── Analytical — subconscious brain (skills, workflows, goals, naming)
|
|
63
|
-
├── Skills — domain knowledge bundles (Markdown, user-extensible)
|
|
64
|
-
├── Workflows — operational recipes for multi-step tasks
|
|
65
|
-
├── MCP — external tool integration (Model Context Protocol)
|
|
66
|
-
├── Sub-agents — autonomous child sessions with lossless context inheritance
|
|
67
|
-
├── Mneme — memory department (summarization, compression, pinning, recall)
|
|
68
|
-
│
|
|
69
|
-
│ Designed:
|
|
70
|
-
├── Thymos — hormonal/desire system (stimulus → hormone vector)
|
|
71
|
-
└── Psyche — soul matrix (coefficient table, evolving individuality)
|
|
72
|
-
```
|
|
61
|
+
Anima splits into two processes. The **Brain** is persistent — it handles LLM calls, tool execution, event processing, and state. The **TUI** is a stateless client — it connects via WebSocket, renders events, captures input. If the TUI disconnects, the brain keeps running; when it reconnects, the session resumes with chat history preserved.
|
|
73
62
|
|
|
74
|
-
|
|
63
|
+
Inside the Brain, three independent LLM processes run in parallel on a shared event bus, named after the three original Muses described by Pausanias. They don't call each other — they all react to the same stream of events, and their outputs combine.
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
├── Agent loop + tool execution ├── Terminal rendering
|
|
80
|
-
├── Analytical brain (background) └── User input capture
|
|
81
|
-
├── Mneme memory department (background)
|
|
82
|
-
├── Skills registry + activation
|
|
83
|
-
├── Workflow registry + activation
|
|
84
|
-
├── MCP client (HTTP + stdio)
|
|
85
|
-
├── Sub-agent spawning
|
|
86
|
-
├── Event bus + persistence
|
|
87
|
-
├── Solid Queue (background jobs)
|
|
88
|
-
├── Action Cable (WebSocket server)
|
|
89
|
-
└── SQLite databases ◄── WebSocket (port 42134) ──► TUI
|
|
90
|
-
```
|
|
65
|
+
### Three Muses
|
|
66
|
+
|
|
67
|
+
**Aoide — the performer.** The main LLM (Claude Opus 4.6), the muse of voice and performance. Thinks, decides, uses tools, talks to the user. Reads a system prompt assembled fresh every turn (soul + sisters block + tool menu + snapshots) and a live **viewport** of events from the database — never a static array. Everything the agent outputs is Aoide; her sisters stay silent in her voice.
|
|
91
68
|
|
|
92
|
-
|
|
69
|
+
**Melete — the preparer.** A separate LLM process (Claude Haiku 4.5) that runs as Aoide's subconscious between turns. She observes the conversation and handles everything Aoide shouldn't break flow for: activating relevant skills, managing workflows, tracking goals, naming the session. The first microservice on Anima's event bus — the working proof that background subscribers scale. → [Preparation as a Second Brain (Melete)](#preparation-as-a-second-brain-melete)
|
|
93
70
|
|
|
94
|
-
|
|
71
|
+
**Mneme — the rememberer.** The third muse, running on the same event bus, specializing in one job: making sure nothing important is ever truly lost. She summarizes what's about to leave the viewport, compresses short-term memories into long-term, pins critical events to active goals, and surfaces relevant older context automatically via passive recall. Biology, not a filing cabinet. → [Semantic Memory (Mneme)](#semantic-memory-mneme)
|
|
95
72
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| Database | SQLite (3 databases per environment: primary, queue, cable) |
|
|
100
|
-
| Event system | Rails Structured Event Reporter + Action Cable bridge |
|
|
101
|
-
| LLM integration | Anthropic API (Claude Opus 4.6 + Claude Haiku 4.5) |
|
|
102
|
-
| External tools | Model Context Protocol (HTTP + stdio transports) |
|
|
103
|
-
| Transport | Action Cable WebSocket (Solid Cable adapter) |
|
|
104
|
-
| Background jobs | Solid Queue |
|
|
105
|
-
| Interface | TUI via RatatuiRuby (WebSocket client) |
|
|
106
|
-
| Configuration | TOML with hot-reload (`Anima::Settings`) |
|
|
107
|
-
| Process management | Foreman |
|
|
108
|
-
| Distribution | RubyGems (`gem install anima-core`) |
|
|
73
|
+
Two more subsystems are designed but not yet implemented: **Thymos** (a hormonal/desire subscriber) and **Psyche** (a coefficient matrix for evolving individuality). Both plug into the same event bus as Melete and Mneme — no orchestrator, no central loop, just more independent subscribers reacting to the same stream.
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
109
76
|
|
|
110
77
|
### Distribution Model
|
|
111
78
|
|
|
112
79
|
Anima is a Rails app distributed as a gem, following Unix philosophy: immutable program separate from mutable data.
|
|
113
80
|
|
|
81
|
+
**Requirements:** Ruby 3.4+, `tmux` (used as the persistent shell backend for the bash tool), `gh` (GitHub CLI, for issue/PR tools).
|
|
82
|
+
|
|
114
83
|
```bash
|
|
115
84
|
gem install anima-core # Install the Rails app as a gem
|
|
116
85
|
anima install # Create ~/.anima/, set up databases, start brain as systemd service
|
|
@@ -129,7 +98,8 @@ State directory (`~/.anima/`):
|
|
|
129
98
|
```
|
|
130
99
|
~/.anima/
|
|
131
100
|
├── soul.md # Agent's self-authored identity (always in context)
|
|
132
|
-
├── config.toml #
|
|
101
|
+
├── config.toml # Brain settings (hot-reloadable)
|
|
102
|
+
├── tui.toml # TUI settings (hot-reloadable)
|
|
133
103
|
├── mcp.toml # MCP server configuration
|
|
134
104
|
├── config/
|
|
135
105
|
│ └── credentials/ # Rails encrypted credentials (includes AR encryption keys)
|
|
@@ -141,7 +111,7 @@ State directory (`~/.anima/`):
|
|
|
141
111
|
└── tmp/
|
|
142
112
|
```
|
|
143
113
|
|
|
144
|
-
Updates: `anima update` — upgrades the gem, merges new config settings into
|
|
114
|
+
Updates: `anima update` — upgrades the gem, merges new config settings into both `config.toml` and `tui.toml` without overwriting customized values, and restarts the systemd service if it's running. Use `anima update --migrate-only` to skip the gem upgrade and only add missing config keys.
|
|
145
115
|
|
|
146
116
|
### Authentication Setup
|
|
147
117
|
|
|
@@ -169,8 +139,8 @@ The agent has access to these built-in tools:
|
|
|
169
139
|
| `spawn_specialist` | Spawn a named specialist sub-agent from the registry |
|
|
170
140
|
| `spawn_subagent` | Spawn a generic child session with custom tool grants |
|
|
171
141
|
| `think` | Think out loud or silently — reasoning step between tool calls |
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
142
|
+
| `search_messages` | Keyword sweep across long-term memory (FTS5). Returns ranked snippets with message IDs for drill-down |
|
|
143
|
+
| `view_messages` | Fractal window around a past message — full detail at the center, compressed snapshots at the edges |
|
|
174
144
|
| `open_issue` | File a self-improvement issue when something is broken, missing, or could be better |
|
|
175
145
|
| `mark_goal_completed` | Sub-agent only: signal task completion and deliver results to parent |
|
|
176
146
|
|
|
@@ -178,7 +148,7 @@ Plus dynamic tools from configured MCP servers, namespaced as `server_name__tool
|
|
|
178
148
|
|
|
179
149
|
### Sub-Agents
|
|
180
150
|
|
|
181
|
-
Sub-agents aren't processes — they're sessions on the same event bus. When a sub-agent spawns,
|
|
151
|
+
Sub-agents aren't processes — they're sessions on the same event bus. When a sub-agent spawns, it starts with a clean context: a system prompt (identity + communication instructions), a Goal from the task description, and a single user message containing the task — auto-pinned so it survives viewport eviction. No parent conversation history. Sub-agents inherit the parent shell's working directory at spawn time and use a separate model and token budget (configurable via `subagent_model` and `subagent_token_budget`).
|
|
182
152
|
|
|
183
153
|
Two types:
|
|
184
154
|
|
|
@@ -194,24 +164,25 @@ Two types:
|
|
|
194
164
|
|
|
195
165
|
**Generic Sub-agents** — child sessions with custom tool grants for ad-hoc tasks. Each generic sub-agent gets a Haiku-generated nickname (e.g. `@loop-sleuth`, `@api-scout`) for @mention addressing.
|
|
196
166
|
|
|
197
|
-
Each sub-agent is spawned with a single **Goal**
|
|
167
|
+
Each sub-agent is spawned with a single **Goal** from its task description and a pinned user message containing the task text. When done, the sub-agent calls `mark_goal_completed` to deliver results to the parent — this is the explicit finish line that prevents runaway agents. Sub-agents also get half the main agent's thinking budget to limit scope creep.
|
|
198
168
|
|
|
199
169
|
Between spawn and completion, sub-agents communicate through natural text — their `agent_message` events route to the parent session automatically, and the parent replies via `@name` mentions. Workers become colleagues.
|
|
200
170
|
|
|
201
171
|
### Skills
|
|
202
172
|
|
|
203
|
-
Domain knowledge bundles loaded from Markdown files. Skills provide specialized expertise that
|
|
173
|
+
Domain knowledge bundles loaded from Markdown files. Skills provide specialized expertise that Melete activates based on conversation context. Skill content enters the conversation as phantom tool_use/tool_result pairs through the `PendingMessage` promotion flow — the same mechanism used for sub-agent messages. This keeps the system prompt stable for prompt caching while skills flow through the sliding window like regular messages.
|
|
204
174
|
|
|
205
175
|
- **Built-in skills:** ActiveRecord, Draper decorators, DragonRuby, MCP server, RatatuiRuby, RSpec, GitHub issues
|
|
206
176
|
- **User skills:** Drop `.md` files into `~/.anima/skills/` to add custom knowledge
|
|
207
177
|
- **Override:** User skills with the same name replace built-in ones
|
|
208
178
|
- **Format:** Flat files (`skill-name.md`) or directories (`skill-name/SKILL.md` with `examples/` and `references/`)
|
|
179
|
+
- **Viewport deduplication:** Melete's skill catalog excludes skills already visible in the viewport, preventing redundant activation
|
|
209
180
|
|
|
210
181
|
Active skills are displayed in the TUI HUD panel (toggle with `C-a → h`).
|
|
211
182
|
|
|
212
183
|
### Workflows
|
|
213
184
|
|
|
214
|
-
Operational recipes that describe multi-step tasks. Unlike skills (domain knowledge), workflows describe WHAT to do.
|
|
185
|
+
Operational recipes that describe multi-step tasks. Unlike skills (domain knowledge), workflows describe WHAT to do. Melete activates a workflow when she recognizes a matching task and converts the prose into tracked goals. Like skills, workflow content enters the conversation as a `from_melete` phantom pair through the `PendingMessage` flow and rides the viewport until it evicts — there is no explicit deactivation.
|
|
215
186
|
|
|
216
187
|
- **Built-in workflows:** `feature`, `commit`, `create_plan`, `implement_plan`, `review_pr`, `create_note`, `research_codebase`, `decompose_ticket`, and more
|
|
217
188
|
- **User workflows:** Drop `.md` files into `~/.anima/workflows/` to add custom workflows
|
|
@@ -231,7 +202,7 @@ description: "Capture findings or context as a persistent note."
|
|
|
231
202
|
You are tasked with capturing content as a persistent note...
|
|
232
203
|
```
|
|
233
204
|
|
|
234
|
-
The active workflow is shown in the TUI HUD panel with a 📜 indicator. The full lifecycle — activation, goal creation, execution, deactivation — is managed by
|
|
205
|
+
The active workflow is shown in the TUI HUD panel with a 📜 indicator. The full lifecycle — activation, goal creation, execution, deactivation — is managed by Melete using judgment, not hardcoded triggers.
|
|
235
206
|
|
|
236
207
|
### MCP Integration
|
|
237
208
|
|
|
@@ -269,24 +240,11 @@ anima mcp secrets remove linear_api_key # Remove secret
|
|
|
269
240
|
|
|
270
241
|
Secrets are stored in an encrypted database table (Active Record Encryption) and interpolated via `${credential:key_name}` syntax in any TOML string value.
|
|
271
242
|
|
|
272
|
-
### Analytical Brain
|
|
273
|
-
|
|
274
|
-
A separate LLM process that runs as the agent's subconscious — the first microservice in Anima's brain architecture. For the full motivation behind this design, see [LLMs Have ADHD: Why Your AI Agent Needs a Second Brain](https://blog.promptmaster.pro/posts/llms-have-adhd/).
|
|
275
|
-
|
|
276
|
-
The analytical brain observes the main conversation between turns and handles everything the main agent shouldn't interrupt its flow for:
|
|
277
|
-
|
|
278
|
-
- **Skill activation** — activates/deactivates domain knowledge based on conversation context
|
|
279
|
-
- **Workflow management** — recognizes tasks, activates matching workflows, tracks lifecycle
|
|
280
|
-
- **Goal tracking** — creates root goals and sub-goals as work progresses, marks them complete, evicts finished goals from context after a configurable message threshold
|
|
281
|
-
- **Session naming** — generates emoji + short name when the topic becomes clear
|
|
282
|
-
|
|
283
|
-
Each of these would be a context switch for the main agent — a chore that competes with the primary task. For the analytical brain, they ARE the primary task. Two agents, each in their own flow state.
|
|
284
|
-
|
|
285
|
-
Goals form a two-level hierarchy (root goals with sub-goals) and are displayed in the TUI. The analytical brain uses a fast model (Claude Haiku 4.5) for speed and runs as a non-persisted "phantom" session.
|
|
286
|
-
|
|
287
243
|
### Configuration
|
|
288
244
|
|
|
289
|
-
|
|
245
|
+
Brain and TUI have separate config files — both hot-reloadable (no restart needed).
|
|
246
|
+
|
|
247
|
+
**Brain settings** (`~/.anima/config.toml`):
|
|
290
248
|
|
|
291
249
|
```toml
|
|
292
250
|
[llm]
|
|
@@ -294,32 +252,51 @@ model = "claude-opus-4-6"
|
|
|
294
252
|
fast_model = "claude-haiku-4-5"
|
|
295
253
|
max_tokens = 8192
|
|
296
254
|
max_tool_rounds = 250
|
|
297
|
-
token_budget =
|
|
255
|
+
token_budget = 120_000
|
|
256
|
+
subagent_model = "claude-sonnet-4-6"
|
|
257
|
+
subagent_token_budget = 90_000
|
|
298
258
|
|
|
299
259
|
[timeouts]
|
|
300
260
|
api = 300
|
|
301
261
|
command = 30
|
|
302
262
|
|
|
303
|
-
[
|
|
304
|
-
completed_decay_messages = 5
|
|
305
|
-
|
|
306
|
-
[analytical_brain]
|
|
263
|
+
[melete]
|
|
307
264
|
max_tokens = 4096
|
|
308
265
|
blocking_on_user_message = true
|
|
309
266
|
message_window = 20
|
|
310
267
|
|
|
311
268
|
[session]
|
|
312
269
|
default_view_mode = "basic"
|
|
313
|
-
name_generation_interval = 30
|
|
314
270
|
```
|
|
315
271
|
|
|
272
|
+
**TUI settings** (`~/.anima/tui.toml`):
|
|
273
|
+
|
|
274
|
+
```toml
|
|
275
|
+
[connection]
|
|
276
|
+
default_host = "localhost:42134" # Override per-launch with --host
|
|
277
|
+
|
|
278
|
+
[chat]
|
|
279
|
+
scroll_step = 1
|
|
280
|
+
viewport_back_buffer = 3
|
|
281
|
+
|
|
282
|
+
[theme]
|
|
283
|
+
rate_limit_warning = 70 # Yellow at 70%
|
|
284
|
+
rate_limit_critical = 90 # Red at 90%
|
|
285
|
+
user_message_bg = 22 # 256-color: dark green
|
|
286
|
+
assistant_message_bg = 17 # 256-color: dark navy
|
|
287
|
+
scrollbar_thumb = "cyan"
|
|
288
|
+
border_focused = "yellow"
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The TUI is a standalone client with zero Rails dependency. Its settings cover connection tuning, scroll behavior, terminal watchdog, theme colors, and performance logging. See `~/.anima/tui.toml` for all available options.
|
|
292
|
+
|
|
316
293
|
## Design
|
|
317
294
|
|
|
318
295
|
### Three Layers (mirroring biology)
|
|
319
296
|
|
|
320
|
-
1. **Cortex (
|
|
297
|
+
1. **Cortex (Aoide)** — the main LLM, the muse of performance. Thinking, decisions, tool use. Reads the system prompt (soul + sisters + tool menu + snapshots) and the event viewport. This layer is fully implemented.
|
|
321
298
|
|
|
322
|
-
2. **Endocrine system (Thymos)** [planned] — a lightweight background process. Reads recent events. Doesn't respond. Just updates hormone levels. Pure stimulus→response, like a biological gland.
|
|
299
|
+
2. **Endocrine system (Thymos)** [planned] — a lightweight background process. Reads recent events. Doesn't respond. Just updates hormone levels. Pure stimulus→response, like a biological gland. Melete is the architectural proof that background subscribers work — Thymos plugs into the same event bus.
|
|
323
300
|
|
|
324
301
|
3. **Homeostasis** [planned] — persistent state (SQLite). Current hormone levels with decay functions. No intelligence, just state that changes over time. The cortex reads hormone state transformed into **desire descriptions** — not "longing: 87" but "you want to see them." Humans don't see cortisol levels, they feel anxiety.
|
|
325
302
|
|
|
@@ -341,35 +318,33 @@ Events flow through two channels:
|
|
|
341
318
|
1. **In-process** — Rails Structured Event Reporter (local subscribers like Persister)
|
|
342
319
|
2. **Over the wire** — Action Cable WebSocket (`Event::Broadcasting` callbacks push to connected TUI clients)
|
|
343
320
|
|
|
344
|
-
Events fire, subscribers react, state updates. The system prompt — soul,
|
|
321
|
+
Events fire, subscribers react, state updates. The system prompt — soul, sisters block, tool menu, and snapshots — is assembled fresh for each LLM call. Skills, workflows, and goals flow through the message stream as phantom tool pairs instead, keeping the system prompt stable for prompt caching. The agent's identity (soul.md) is always current, never stale.
|
|
345
322
|
|
|
346
323
|
### Context as Viewport, Not Tape
|
|
347
324
|
|
|
348
325
|
Most agents treat context as an append-only array — messages go in, they never come out (until compaction destroys them). Anima has no array. There are only events persisted in SQLite, and a **viewport** assembled fresh for every LLM call.
|
|
349
326
|
|
|
350
|
-
The viewport is a live query, not a log. It walks events newest-first until the token budget is exhausted. Events that fall out of the viewport aren't deleted — they're still in the database, just not visible to the model right now. The context can shrink, grow, or change composition between any two iterations. If
|
|
327
|
+
The viewport is a live query, not a log. It walks events newest-first until the token budget is exhausted. Events that fall out of the viewport aren't deleted — they're still in the database, just not visible to the model right now. The context can shrink, grow, or change composition between any two iterations. If Melete marks a large accidental file read as irrelevant, it's gone from the next viewport — tokens recovered instantly.
|
|
351
328
|
|
|
352
|
-
This means sessions are endless. No compaction. No lossy rewriting. The model always operates in fresh, high-quality context. The [dumb zone](https://github.com/humanlayer/advanced-context-engineering-for-coding-agents/blob/main/ace-fca.md) never arrives. Meanwhile, Mneme runs as a background
|
|
329
|
+
This means sessions are endless. No compaction. No lossy rewriting. The model always operates in fresh, high-quality context. The [dumb zone](https://github.com/humanlayer/advanced-context-engineering-for-coding-agents/blob/main/ace-fca.md) never arrives. Meanwhile, Mneme runs as a background muse — summarizing evicted events into persistent snapshots so past context is preserved, not destroyed.
|
|
353
330
|
|
|
354
|
-
Sub-agent viewports
|
|
331
|
+
Sub-agent viewports use the same mechanism — their own events only, no parent context inheritance. The parent provides context through the task description, and the sub-agent builds its own conversation from a clean slate.
|
|
355
332
|
|
|
356
333
|
### Brain as Microservices on a Shared Event Bus
|
|
357
334
|
|
|
358
|
-
The
|
|
359
|
-
|
|
360
|
-
Anima mirrors this with an event-driven architecture. The analytical brain is the first subscriber — a working proof that the pattern scales. Future subscribers plug into the same bus:
|
|
335
|
+
The prefrontal cortex doesn't "call" the amygdala. Dozens of specialized subsystems react to the same chemical and electrical signals independently, and their outputs combine — no central coordinator, no blocking RPC, no orchestrator deciding the order of thoughts. Anima mirrors this with an event bus. Melete is the first subscriber that proves the pattern scales; Mneme is the second. Future subscribers plug into the same bus:
|
|
361
336
|
|
|
362
337
|
```
|
|
363
338
|
Event: "tool_call_failed"
|
|
364
339
|
│
|
|
365
|
-
├──
|
|
340
|
+
├── Melete: update goals, check if workflow needs changing
|
|
366
341
|
├── Mneme: summarize evicted context into snapshot
|
|
367
342
|
├── Thymos subscriber: frustration += 10 [planned]
|
|
368
343
|
└── Psyche subscriber: update coefficient (this agent handles errors calmly) [planned]
|
|
369
344
|
|
|
370
345
|
Event: "user_sent_message"
|
|
371
346
|
│
|
|
372
|
-
├──
|
|
347
|
+
├── Melete: activate relevant skills, name session
|
|
373
348
|
├── Mneme: check viewport eviction, fire if boundary left viewport
|
|
374
349
|
├── Thymos subscriber: oxytocin += 5 (bonding signal) [planned]
|
|
375
350
|
└── Psyche subscriber: associate emotional state with topic [planned]
|
|
@@ -377,11 +352,26 @@ Event: "user_sent_message"
|
|
|
377
352
|
|
|
378
353
|
Each subscriber is a microservice — independent, stateless, reacting to the same event bus. No orchestrator decides what to do. The architecture IS the nervous system.
|
|
379
354
|
|
|
355
|
+
### Preparation as a Second Brain (Melete)
|
|
356
|
+
|
|
357
|
+
Every agent today does everything with one brain. Skill selection, workflow tracking, goal management, session naming — all of it competes with the primary task for the same context window and the same attention. Each of these is a micro-task that requires the agent to stop thinking about the real work, do the bookkeeping, and try to pick up where it left off. Flow breaks on every interruption. The full motivation is in [LLMs Have ADHD: Why Your AI Agent Needs a Second Brain](https://blog.promptmaster.pro/posts/llms-have-adhd/).
|
|
358
|
+
|
|
359
|
+
Melete is the answer: a second LLM process that runs between turns as Aoide's subconscious. She observes the conversation and handles everything Aoide shouldn't break flow for:
|
|
360
|
+
|
|
361
|
+
- **Skill activation** — recognizes when a domain becomes relevant and activates matching skill content into Aoide's viewport. A skill rides the viewport as a `from_melete` phantom pair until it naturally evicts — there is no deactivation.
|
|
362
|
+
- **Workflow management** — recognizes multi-step tasks, activates matching workflows, and tracks their lifecycle from start to finish.
|
|
363
|
+
- **Goal tracking** — creates root goals and sub-goals as work progresses, marks them complete, evicts finished goals from context after a configurable message threshold.
|
|
364
|
+
- **Session naming** — generates an emoji + short name the moment the topic becomes clear.
|
|
365
|
+
|
|
366
|
+
Each of these would be a context switch for Aoide — a chore that competes with the primary task. For Melete, they ARE the primary task. Two muses, each in her own flow state.
|
|
367
|
+
|
|
368
|
+
Goals form a two-level hierarchy (root goals with sub-goals) and are displayed in the TUI HUD. Melete uses a fast model (Claude Haiku 4.5) for speed and runs as a non-persisted "phantom" session: she emits events for activation tools but no trace of her own reasoning lands in the database. Her decisions reach Aoide only through the skills, workflows, goals, and names she leaves behind.
|
|
369
|
+
|
|
380
370
|
### Semantic Memory (Mneme)
|
|
381
371
|
|
|
382
372
|
Every AI agent today has the same disability: amnesia. Context fills up, gets compacted, gets destroyed. The agent gets dumber as the conversation gets longer. When the session ends, everything is gone. Some systems bolt on memory as an afterthought — markdown files with procedures for when to save and what format to use. Filing cabinets the agent has to consciously decide to open, mid-task, while in flow. It never does. The truck is already moving.
|
|
383
373
|
|
|
384
|
-
Mneme is not a filing cabinet.
|
|
374
|
+
Mneme is not a filing cabinet. She's *remembering* — the way biological memory works. Continuous, automatic, layered. The third muse running on the same event bus as Aoide and Melete, specializing in one job: making sure nothing important is ever truly lost.
|
|
385
375
|
|
|
386
376
|
**Eviction-triggered summarization** — Mneme tracks a boundary event on each session. When that event leaves the viewport, Mneme fires: it builds a compressed view of the conversation (full text for messages, `[N tools called]` counters for tool work), sends it to a fast model, and persists a snapshot. The boundary advances after each run — a self-regulating cycle that fires exactly when context is about to be lost, no sooner or later. No timer. No manual trigger. The architecture itself knows when to remember.
|
|
387
377
|
|
|
@@ -398,16 +388,40 @@ Mneme is not a filing cabinet. It's *remembering* — the way biological memory
|
|
|
398
388
|
|
|
399
389
|
**Goal-scoped event pinning** — some moments are too important for summaries. Exact user instructions. Key decisions. Critical corrections. Mneme pins these events to active Goals — they float above the sliding window, protected from eviction, surviving intact where compression would lose the nuance that matters. Pins are goal-scoped and many-to-many: one event can attach to multiple Goals, and cleanup is automatic via reference counting. When the last active Goal completes, the pin releases. No manual unpin, no stale pins accumulating forever.
|
|
400
390
|
|
|
401
|
-
**Associative recall** — FTS5 full-text search across the entire
|
|
391
|
+
**Associative recall** — FTS5 full-text search across the entire message history, across all sessions. Two modes: *passive* recall triggers automatically when goals change — Mneme searches for relevant older context and injects it into the viewport between snapshots and the sliding window as `from_mneme` phantom pairs. Memories surface on their own, right after the soul, right before the present. Aoide doesn't have to decide to remember — the remembering happens around her. *Active* search is available to Aoide through `search_messages(query:)` (keyword sweep across long-term memory) and `view_messages(message_id:)` (fractal window around a specific message — full detail at the center, compressed snapshots at the edges, like eye focus with sharp fovea and blurry periphery).
|
|
402
392
|
|
|
403
393
|
The difference from every other system: memory isn't a tool the agent uses. It's the substrate the agent thinks in. Every LLM call assembles a fresh viewport where identity comes first, then memories, then the present — the agent always knows who it is, always has access to what it learned, and never has to break flow to make that happen.
|
|
404
394
|
|
|
405
395
|
### TUI HUD & View Modes
|
|
406
396
|
|
|
407
|
-
The right-side HUD panel shows session state at a glance: session name, goals (with status icons), active skills, workflow, and sub-agents. Toggle with `C-a → h`; when hidden, the input border shows `C-a → h HUD` as a reminder.
|
|
397
|
+
The right-side HUD panel shows session state at a glance: session name, goals (with status icons), active skills, workflow, and sub-agents. Toggle with `C-a → h`; when hidden, the input border shows `C-a → h HUD` as a reminder. The sub-agent list mirrors what Aoide actually carries in her viewport: once Mneme eviction takes the last spawn pair or `from_<nickname>` response out of the sliding window, the entry drops from the HUD; if a later response reintroduces a trace, the entry comes back.
|
|
408
398
|
|
|
409
399
|
**Braille spinner**: An animated braille character (U+2800-U+28FF) replaces the old "Thinking..." label in both the chat viewport and HUD. Each processing state has a distinct animation pattern — smooth snake rotation for LLM generation, staccato pulse for tool execution, rapid deceleration for interrupting. Sub-agents in the HUD show state-driven icons: `●` (generating, green), `◉` (tool executing, green), `●` (interrupting, red), `◌` (idle, grey).
|
|
410
400
|
|
|
401
|
+
**Token Economy HUD**: A fixed panel at the bottom of the HUD displays API economics extracted from every Anthropic response:
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
╭ 📊 Token Economy ────────────────────╮
|
|
405
|
+
│ 5h ░░░░░░░░ 1% ➞3h42m │
|
|
406
|
+
│ 7d ▓▓▓▓▓▓▓▓ 98% │
|
|
407
|
+
│ ⚡ ▓▓▓▓▓▓░░ 69% │
|
|
408
|
+
│ 💾 6.3K tokens │
|
|
409
|
+
│ ⠛⣿⣷⣶⣿⣿⣿⣿⣷⣶⣿⣿⣿ │
|
|
410
|
+
│ 🟢 Verbose │
|
|
411
|
+
╰──────────────────────────────────────╯
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
| Row | Description |
|
|
415
|
+
|-----|-------------|
|
|
416
|
+
| `5h` | 5-hour rate limit utilization with progress bar and reset countdown |
|
|
417
|
+
| `7d` | 7-day rate limit utilization with progress bar |
|
|
418
|
+
| `⚡` | Cache hit rate of the latest call — percentage of input tokens served from cache |
|
|
419
|
+
| `💾` | Tokens served from cache on the latest call |
|
|
420
|
+
| `⠛⣿` | Braille sparkline — per-call cache hit history (2 calls per character); drops signal cache busts |
|
|
421
|
+
| `🟢` | Connection status and current view mode |
|
|
422
|
+
|
|
423
|
+
Progress bars are color-coded: green (< 70%), yellow (70-89%), red (>= 90%) for rate limits; inverted for cache hits (green >= 70%, red < 30%). All data comes from Anthropic API response headers and usage objects, broadcast as message metadata via ActionCable.
|
|
424
|
+
|
|
411
425
|
When content exceeds the panel height, the HUD scrolls. Three input methods:
|
|
412
426
|
|
|
413
427
|
| Input | Action |
|
|
@@ -419,7 +433,7 @@ When content exceeds the panel height, the HUD scrolls. Three input methods:
|
|
|
419
433
|
| `Escape` or `C-a` | Exit HUD focus mode |
|
|
420
434
|
| Mouse wheel over HUD | Scroll without entering focus mode |
|
|
421
435
|
|
|
422
|
-
**Escape key interrupt:** Press `Escape` while the agent is working to
|
|
436
|
+
**Escape key interrupt:** Press `Escape` while the agent is working to signal an interrupt. Running shell commands cooperatively abort — they receive Ctrl+C and return partial output tagged `Your human wants your attention`, which the LLM sees on the next round and pivots from. The interrupt cascades to active sub-agents.
|
|
423
437
|
|
|
424
438
|
Three switchable view modes let you control how much detail the TUI shows. Cycle with `C-a → v`:
|
|
425
439
|
|
|
@@ -432,8 +446,8 @@ Three switchable view modes let you control how much detail the TUI shows. Cycle
|
|
|
432
446
|
View modes are implemented as a three-layer decorator architecture:
|
|
433
447
|
|
|
434
448
|
- **ToolDecorator** (server-side, pre-event) — transforms raw tool responses for LLM consumption. Content-Type dispatch converts HTML → Markdown, JSON → TOON. Sits between tool execution and the event stream.
|
|
435
|
-
- **EventDecorator** (server-side, Draper) — uniform per
|
|
436
|
-
- **TUI Decorator** (client-side) — unique per tool name (`BashDecorator`, `ReadDecorator`, `EditDecorator`, etc.). Decides HOW each tool looks on screen — tool-specific icons, colors, and formatting.
|
|
449
|
+
- **EventDecorator** (server-side, Draper) — uniform per message type (`UserMessageDecorator`, `ToolCallDecorator`, etc.) for promoted messages, and a parallel family (`PendingUserMessageDecorator`, `PendingToolResponseDecorator`, `PendingSubagentDecorator`, `PendingFromMnemeDecorator`, `PendingFromMelete{Skill,Workflow,Goal}Decorator`) for in-flight `PendingMessage` rows. Decides WHAT structured data enters the wire for each view mode; pending payloads carry `status: "pending"` so the TUI dims them.
|
|
450
|
+
- **TUI Decorator** (client-side) — unique per tool name (`BashDecorator`, `ReadDecorator`, `EditDecorator`, etc.). Decides HOW each tool looks on screen — tool-specific icons, colors, and formatting. Honors `status: "pending"` to render in-flight content in the muted theme color.
|
|
437
451
|
|
|
438
452
|
Mode is stored on the `Session` model server-side, so it persists across reconnections.
|
|
439
453
|
|
|
@@ -605,11 +619,11 @@ This single example demonstrates every core principle:
|
|
|
605
619
|
|
|
606
620
|
- Event-driven architecture on a shared event bus
|
|
607
621
|
- Dynamic viewport context assembly (endless sessions, no compaction)
|
|
608
|
-
-
|
|
609
|
-
- Mneme memory
|
|
622
|
+
- Melete, muse of practice (skills, workflows, goals, session naming)
|
|
623
|
+
- Mneme, muse of memory (eviction-triggered summarization, persistent snapshots, goal-scoped event pinning, associative recall)
|
|
610
624
|
- 12 built-in tools + MCP integration (HTTP + stdio transports)
|
|
611
625
|
- 7 built-in skills + 13 built-in workflows (user-extensible)
|
|
612
|
-
- Sub-agents with
|
|
626
|
+
- Sub-agents with isolated context (5 specialists + generic)
|
|
613
627
|
- Client-server architecture with WebSocket transport + graceful reconnection
|
|
614
628
|
- Collapsible HUD panel with goals, skills, workflow, and sub-agent tracking
|
|
615
629
|
- Three TUI view modes (Basic / Verbose / Debug)
|