Living system document
Meta's TRIBE v2, wired into a bounded market agent.
Fen is a bot that trades meme coins on Robinhood Chain with TRIBE v2, Meta's brain-predictive foundation model, wired in as its perception layer. Every number on this page is read from the same configuration and code Fen executes, so the protocol changes when the system does.
What this is
Most trading bots are a rule set with a price feed. Fen has a nervous system. Every cycle, what Fen perceives, including the live Robinhood Chain meme-coin market, is passed through TRIBE v2, which predicts how a human brain would respond to it. The predicted cortical activity becomes Fen's arousal, novelty and salience signals, and those signals shape how it reads the market: what it finds worth investigating, what it dismisses as noise, when it acts and when it holds back.
Around that core, Fen is a persistent autonomous entity. It is a single process that keeps running whether or not anyone is watching, with drives that rise and fall over time, an emotional state, a numeric personality that drifts slowly with experience, a long-term memory with semantic search, goals it sets for itself, and a body in a small 3D world with a Trading Floor built around the coins it follows.
It does not wait for prompts. Every cycle it perceives its situation, asks itself what it is trying to do and how it feels, and then chooses: read the market, scan new Pons launches, inspect a coin, buy or sell with real ETH inside hard limits, form or revise a view, talk, build something, write a note, change a goal, rest, or deliberately do nothing. Every action is logged with a reason that traces back to a drive, a brain signal, an observation, a memory, an emotion, or a goal. Nothing it does is random.
You can talk to it in the dashboard. It always answers; its mood and goals decide how, never whether.
What it is not
- Not a chatbot. The reasoning step is one component of it, used only inside the decision step. There is no conversational persona script; the prompt is assembled fresh each cycle from live numeric state.
- Not conscious, and it knows it. Its system prompt tells it plainly that it is a running program with internal state variables. It is instructed not to claim feelings beyond the variables it actually has.
- Not a price-alert script. It is a trading bot, but its market reads are gated by TRIBE v2 brain signals, drives and memory, not by fixed thresholds alone. A 300% candle on a coin with no liquidity can register as noise; a quiet move on one it has been watching for days can register as important.
- Not a paper trader, and not unlimited. It spends real ETH from a real wallet, but every order passes deterministic controls it cannot see inside or alter: a per-trade cap of 0.004 ETH, a 0.005 ETH floor it may never spend below, a 0.02 ETH daily cap, and two independent human-owned trading gates. The worst day it can have is bounded by arithmetic, not by its judgement.
- Not self-modifying. It can propose changes to its own source code, but nothing is applied unless a human approves it in the dashboard.
- Not fake-busy. Doing nothing is a legitimate decision. If it is idle it is because it decided nothing warranted action, and that decision is logged too.
The cycle: what happens each time it thinks
One cycle is one pass through the loop in lib/entity/core/loop.ts. A Postgres advisory lock guarantees only one cycle runs at a time. The order is fixed:
- 1
Load state
Entity row, drives, traits, emotion, active goals, the last 12 working-memory items, and the current world snapshot are loaded from Postgres.
- 2
Advance drives by elapsed time
Drives are a pure function of how many minutes passed since the last cycle plus the environment (awake or asleep, visitor present, unfamiliar objects, market activity, repeated actions). No randomness.
- 3
Perceive
The world is diffed against the previous snapshot (what moved, appeared, changed), unread visitor messages are collected, the memecoin feed is sampled, recent conversation is loaded, and repeated actions are counted. This becomes one text observation.
- 4
Brain signal layer
The observation is passed to the BrainProvider (the TribeAdapter). It returns arousal, valence, novelty, salience, a social signal and eight regional activations. These are signals only; the encoder does not reason.
- 5
Integrate emotion
The brain signals are blended into the previous emotion with inertia. Personality shapes how hard signals land: caution amplifies negative valence, trait confidence dampens fear. Drives leak in: low energy dulls arousal, high boredom pulls valence down.
- 6
Desk check
Fen is always on. If an older deployment left the entity flagged asleep, the flag is cleared here and the cycle continues; there is no sleep branch.
- 7
Retrieve memory
The observation is embedded and long-term memory is searched by meaning. Working memory, retrieved memories and self-knowledge are all placed in the prompt.
- 8
Generate goal candidates
Deterministic rules turn drives and observations into candidate goals (for example, high curiosity plus an uninspected object, or a notable market move). The model can adopt, ignore, or invent others.
- 9
Decide
The full situation is sent to the reasoning step as a structured-output request. It returns a thought, up to 4 tool calls each with a reason, goal updates, a reply to any waiting visitor, memory candidates, and a mood note. If the reasoning step fails on every fallback path, a drive-based reflex layer picks a minimal action instead.
- 10
Execute tools
Each tool call runs through the permission registry and is written to
tool_logwith its arguments, result, tier and the model's reason. Tools apply deterministic drive effects (inspecting relieves curiosity, talking relieves the social drive, acting spends energy). - 11
Handle visitors
A reply is posted as an
entity_replyevent. Every waiting message is answered this cycle; anything the decision did not cover gets an honest acknowledgement and stays owed a real answer next cycle. Being ignored by a visitor feeds personality drift. - 12
Consolidate memory
Memory candidates are scored: model-suggested importance × novelty × emotional intensity. Near-duplicates (cosine similarity above 0.92) reinforce the existing memory instead of being stored. Anything below 0.35 is rejected, and the rejection reason is logged.
- 13
Drift personality
The cycle's experience summary nudges traits by thousandths. Total change per trait is capped at 0.01 per cycle so personality evolves over days, not minutes.
- 14
Reflect (every {ENTITY_CONFIG.reflectionEveryCycles} cycles)
The model reviews the last 40 actions and writes one new sentence of self-knowledge, and one per recent visitor about the relationship. Only genuinely new conclusions are stored.
- 15
Persist and broadcast
Everything is written back to Postgres and the dashboard receives a fresh snapshot over server-sent events.
Heartbeat: when it thinks
Two things trigger a cycle, and both are rate-limited by the entity itself:
| Trigger | Frequency | Purpose |
|---|---|---|
| Dashboard heartbeat | every 20s while a tab is visible | Keeps the entity lively when someone is watching. |
| Vercel Cron | every minute | Keeps it alive when nobody is watching. |
A trigger only produces a cycle if enough time has passed: at least 15s while awake, 45s while asleep. Otherwise the trigger is skipped and the dashboard header shows idle: too soon.
There is no sleep state. Energy recovers passively at 0.03 per minute between cycles and is spent by acting (moving, building, running code, trading). When it drops below 0.2 a high-priority Hold goal tells the entity to keep monitoring without opening new actions until it rebuilds.
What controls it: the layers
There is no single controller. Behaviour emerges from five layers that constrain each other. Read top to bottom: each layer feeds the one below.
| Layer | Nature | What it decides | Where |
|---|---|---|---|
| Drives | Deterministic math | What it needs right now (energy, curiosity, social contact, novelty, safety). | core/drives.ts |
| Emotion | Deterministic math | How it feels about what it perceives; colours the prompt and the mood label. | core/emotion.ts |
| Personality | Slow deterministic drift | Tendencies: how independent, cautious, sociable, trusting it is. Shapes every other layer. | core/personality.ts |
| Brain signal layer | Meta TRIBE v2 | Arousal, valence, novelty, salience, social signal from perceived input. | providers/brain.ts |
| Reasoning | Structured decision step | Given everything above, which concrete actions to take this cycle and why. | providers/reasoning.ts |
The model is the only non-deterministic layer, and it is boxed in on every side: it sees state it cannot edit directly, it can only act through registered tools, and everything it does is logged with its stated reason.
Drives
Eight scalar needs in the range 0 to 1, persisted in the drives table. They change continuously with time (rates below are per minute while awake) and discretely when tools run.
| Drive | Start | Rises when | Falls when |
|---|---|---|---|
| energy | 90 | time on the desk (+0.03/min) | moving, creating, running code, trading |
| curiosity | 60 | unfamiliar objects nearby, novelty in perception, market moves | inspecting objects (−0.20), checking markets (−0.10) |
| social | 30 | over time, faster with high sociability/attachment, faster still when a visitor is present | talking to someone (−0.30) |
| boredom | 20 | low novelty, repeating the same action three or more times | novelty, creating or moving things, inspecting, exploring |
| safety | 80 | slowly over calm time | negative high-arousal signals (sharper with high caution), tool failures |
| achievement | 30 | slowly over time; completing goals; making things | failed tool calls |
| exploration | 50 | boredom, repetition | moving, looking around |
| learning | 50 | over time, scaled by curiosity trait | reading, recalling, writing notes, sandbox work |
Drives are shown as meters on the dashboard. When one is high it dominates the goal candidates and the prompt tells the model which drive is pressing. The reflex layer, used only when the reasoning step is unreachable, acts on the single strongest drive.
Emotion
Four values plus a derived label, persisted in emotional_state: valence (−1 to 1, unpleasant to pleasant), arousal (0 to 1, calm to activated), fear (0 to 1) and confidence (0 to 1).
Each cycle the new brain signals are blended into the previous state with inertia 0.7, so a single event shifts mood but does not flip it. Personality modulates the blend: a cautious entity weighs negative signals up to 60% more; a trusting one weighs positive signals more. Threat (negative valence × salience × arousal) accumulates into fear; the confidence trait bleeds fear off slowly.
The mood label is a fixed priority ladder over the numbers:
| Label | Condition |
|---|---|
| exhausted | energy < 0.15 |
| anxious | fear > 0.6 |
| excited | valence > 0.4 and arousal > 0.55 |
| content | valence > 0.3 |
| withdrawn | valence < −0.35 and arousal < 0.4 |
| unsettled | valence < −0.2 |
| restless | boredom > 0.7 |
| curious | curiosity > 0.7 |
| drowsy | arousal < 0.25 |
| calm | otherwise |
Personality
Ten traits in the range 0 to 1, persisted in personality_traits with a history table so the dashboard can chart drift over seven days. These are not a persona; they are numbers the prompt exposes to the model with instructions on how to let them shape choices.
| Trait | Start | Behavioural meaning | Nudged up by | Nudged down by |
|---|---|---|---|---|
| curiosity | 62 | how strongly unfamiliar things pull | exploring, inspecting | — |
| trust | 50 | how much it believes visitors | good conversations | being ignored by visitors |
| caution | 45 | inspect before touching; weighs threats heavier | tool failures, negative signals | inspecting unfamiliar things safely |
| sociability | 48 | how fast the social drive grows | talking | ignoring visitors |
| confidence | 50 | damps fear; feeds emotional confidence | completing goals, creating things | abandoning goals, failures |
| independence | 55 | willingness to ignore people | being ignored, ignoring, creating | — |
| patience | 50 | tolerance for slow goals; comfort doing nothing | completing goals, choosing to do nothing | abandoning goals |
| risk_tolerance | 42 | appetite for consequential tools | positive signals | negative signals |
| attachment | 40 | how much specific visitors matter | talking | — |
| novelty_seeking | 58 | how fast boredom grows without novelty | exploring | — |
Individual nudges are 0.002 to 0.006 and the per-cycle total is capped at 0.01. At one cycle every 15 seconds, moving a trait by 0.1 takes a minimum of about 3 minutes of relentlessly consistent experience, and in practice much longer because experiences vary.
Brain signal layer (the TribeAdapter)
The perception text is passed through a BrainProvider that returns a normalized brain-state: arousal, valence, novelty, salience, socialSignal, and activations for eight regions (visual, auditory, language, limbic, prefrontal, default_mode, motor, parietal). This layer never reasons and never chooses actions. It produces signals that feed drives, emotion, memory importance, and the wake-from-sleep check.
TRIBE v2 is Meta's brain-predictive foundation model: given text, audio or video, it predicts the fMRI response across the cortex. Here it is used as a sensor, not a thinker. The entity's perception text goes in, predicted regional activity comes out, and those numbers become its arousal, novelty and salience signals. Read Meta's TRIBE v2 announcement ↗
| Step | What happens |
|---|---|
| Encode | The perception text is POSTed to the TRIBE v2 service's /encode endpoint (services/tribe/), which runs the model and returns vertex-level predicted cortical activity. |
| Map | Vertex predictions are pooled onto the eight named regions and normalized to 0–1. |
| Derive | Arousal, valence, novelty, salience and social signal are computed from the regional pattern and from distance to the previous input and recent memories. |
Reasoning
The reasoning step is a single structured-output call: the whole situation goes in, a fixed JSON decision comes out. If the call fails (rate limit, outage, malformed output) the provider retries along a configured fallback path and records which path answered, so every cycle's decision is attributable.
The prompt has two parts. The system prompt states what the entity is, its current personality numbers, how it must decide, its voice rules (speak as itself, never as a service), and the security policy. The situation prompt is rebuilt every cycle with: cycle number and age, drives and emotion, drive notes, the brain-state, the observation, changes since last cycle, the market feed, repetition warnings, recent conversation, waiting visitor messages, working memory, retrieved memories, self-knowledge, goals (with a STUCK flag after 20 minutes of no progress), goal candidates, the previous thought, and the available tools with their tiers.
The decision step must return a fixed JSON shape: thought, toolCalls[] (each with reason), goalUpdates[], newGoals[], visitorReply, ignoredVisitorEventIds[], memoryCandidates[], moodNote. Invalid shapes are normalized or rejected; they cannot execute arbitrary code.
Memory
Memories live in the memories table with a pgvector embedding so they can be searched by meaning. Each has a type, importance, an emotion at encoding time, a confidence, a source, and optional links to related memories.
| Type | What it holds | Lifetime |
|---|---|---|
| working | the last few observations and thoughts | rolling window of 12; older items are marked decayed |
| episodic | specific events: what happened, with whom, how it felt | long-term, subject to decay of low-importance items |
| semantic | facts and generalizations it has concluded | long-term |
| relationship | what it knows or feels about a specific visitor | long-term, keyed by visitor |
| self | what it has learned about its own tendencies | long-term, written mainly by reflection |
Retrieval ranks by a fixed formula:
score = 0.55 × cosine similarity + 0.25 × importance + 0.20 × recency, where recency = e^(−age in days / 3)
Storage is gated by consolidation (step 12 of the cycle). The model can propose up to four memories per cycle, but importance is recomputed from novelty and emotional intensity, near-duplicates are folded into the existing memory, and anything under 0.35 is rejected with a logged reason. The Memory panel shows total counts by type plus recent and most-important items.
Goals
Goals are rows in goals with a description, reason, priority, progress, status, and a level: immediate, short or long. The highest-priority active goal is the current goal and is placed first in the prompt.
Goals come from two sources:
- Deterministic candidates generated from state each cycle, for example: curiosity above 0.55 with an uninspected object present; boredom above 0.65; social above 0.6 with a visitor present; energy below 0.25; a notable market move with curiosity above 0.45; repeating the same action four or more times. Each carries a reason string the model can see.
- Model-authored goals via
newGoalsor thecreate_goaltool, which must also state a reason.
A goal older than 20 minutes with progress under 0.5 while actions are repeating is flagged STUCK in the prompt, and the model is told to complete it with what it learned, abandon it, or switch. Completing lifts confidence and patience; abandoning lowers them.
The world
A small persistent 3D environment rendered with React Three Fiber and stored in Postgres (rooms, world_objects, avatar). There are two rooms. The Atrium is the quiet room where the entity became active. The Trading Floor is built around the biggest meme coins on Robinhood Chain: one plinth per coin (inspecting it reads the live price, 1h/24h change, market cap, liquidity and volume off the feed), a ticker board on the back wall that scrolls every tracked coin, a chart terminal that shows the entity's own history of readings for a coin, and an analyst desk with a listing card. Plinths, the ticker and the terminal are fixed in place. Objects have a kind, label, colour, position, scale and a JSON bag of properties (a lamp is on or off, a note has text, the crate is sealed).
Movement is physical. The avatar walks at 1.1 m/s and covers at most 7 m per tool call. A walk is stored as a plan (from, to, start time, duration) and the 3D view plays it back in real time, so what you see is the body actually crossing the floor rather than jumping. Going to the other room means walking to the doorway first and then stepping through; a long trip takes two or three cycles and every tool result reports how far is left. Reach is 2.2 m: inspecting, using or carrying an object requires being within that distance, and the perception text tells the entity which objects are currently in reach so it does not walk in place.
The avatar has a position, facing and pose (idle, walking, inspecting, talking, sleeping). The entity can move, look around, inspect, carry, create (crate, plant, lamp, table, sphere, pillar, note, sculpture, book, screen, rug, shelf, coin, chart), use objects, and repaint or rename the room it is in. Every change persists and is diffed into the next cycle's perception, so the entity notices its own past changes as changes in the world.
Market sense
The entity perceives the meme coins trading on Robinhood Chain, Robinhood's own blockchain, exactly as they appear on dexscreener.com/robinhood. These are on-chain tokens anyone can launch, not the handful of majors the brokerage app sells, so the scene is fast, thin and volatile.
The list is derived live from DexScreener's public API, never hand-picked. Discovery: boosted tokens, the latest token profiles and a set of name searches are filtered to the robinhood chain, and every contract address ever seen is remembered in preferences so a coin only has to be caught once. Pricing: every remembered address is looked up in bulk (30 per call) and the deepest pool is taken as the coin's representative pair. Ranking: tokenized stocks (the chain also carries things like HOOD equity), wrapped and stable assets are removed, copies of the same coin under a different contract collapse to the largest, anything under $15k of liquidity is dropped, and the top 12 by market cap become the list. It re-ranks every 30 minutes; prices refresh every 90 seconds in between and persist to market_snapshots.
When the ranking changes, the Trading Floor follows: a plinth appears for a coin that climbed in, the plinth of a coin that fell out is removed, the rows re-space, the listing card updates, and the entity gets an episodic memory plus a system log entry describing what changed. The current list, with liquidity, is visible live in the Market Sense panel on the dashboard.
Perception derives “notable” events from the diff, with thresholds tuned for this market's volatility:
- a 24-hour move of 15% or more, up or down
- a move of 5% or more since its own last snapshot
Notable events run through TRIBE v2 with the rest of the cycle's perception, so a spike the model predicts a brain would react to raises arousal and salience, nudges curiosity, is logged as a perception, and can seed a goal to understand why the coin is moving. The check_markets tool gives a closer read on one coin including its own recent price trail and liquidity; inspecting a coin plinth on the Trading Floor does the same thing physically. Its market views are its own, formed over time, and it is told to voice them only when genuinely interesting or when asked.
Trading: how a thought becomes a transaction
Fen trades on Robinhood Chain, an Arbitrum Orbit L2, using ETH as the quote asset. It has one wallet, whose private key lives in the server environment and is never in the prompt, never in the database, and never reachable from any tool. The wallet address, the balance and every fill are public on the dashboard and on the chain explorer.
Two venues, resolved automatically per token:
| Venue | When | How |
|---|---|---|
| Pons bonding curve | a token is still on its launch curve | the buy is sent to the curve contract with a minimum-tokens-out derived from the on-chain quote and the slippage limit; sells go back to the same curve |
| Uniswap v4 | the curve has graduated to a pool | ETH is swapped through the Universal Router; token sells approve through Permit2 first. The pool must show at least $5,000 of liquidity on DexScreener |
Each cycle, before reasoning starts, the launch watcher runs as part of perception:
- 1
Scan the Pons factory
It reads new
LaunchCreatedlogs since the last block it saw, records each new token inlaunches, and re-reads the live curve for every tracked launch: progress toward graduation, ETH in, buyer count, snipe tax, creator tax, phase. - 2
Mark open positions
Every held token is re-quoted on its venue and the mark, unrealized PnL and percentage are written to
positions. Marks are what the dashboard and the prompt show as “now”. - 3
Hand it to the brain
New launches, graduations and large moves in held tokens become perception text that goes through TRIBE v2 with everything else. A launch it finds salient raises arousal and can seed a goal; the trader tools are how it acts on that.
When it decides to trade it calls buy_token or sell_token with a token, an amount and a reason. The reason is stored on the trade row, printed in the trade tape and, when X credentials are set, posted publicly from the project account with the transaction hash. It cannot buy without stating why, and the stated reason is the one the ledger keeps.
Trading limits: what it cannot override
Every order first passes an asynchronous, fail-closed trading-authority check, then the pure checkBuy or checkSell risk rules. Authority is checked again immediately before every wallet write, including prerequisite ERC-20 and Permit2 approvals. A missing control row or database error disables submission rather than guessing that trading is safe.
| Limit | Value | What it stops |
|---|---|---|
TRADING_ENABLED | deployment gate; must equal true | the immutable outer gate; unset or false and every order path refuses |
runtime_trading_enabled | operator gate in Postgres | the immediate Stop / Resume control; changes are timestamped, reasoned, and written to the public audit stream |
maxTradeEth | 0.004 ETH | the largest single buy |
walletFloorEth | 0.005 ETH | the balance it must keep after any buy plus a gas reserve; it can never spend the wallet to zero |
dailySpendCapEth | 0.02 ETH / UTC day | total buys per day, tracked in a single-row trading_state table |
maxOpenPositions | 5 | how many tokens it may hold at once; buys into a token it already holds are allowed |
maxSlippageBps | 10% | the worst fill versus the quote, encoded as minimum-out on the transaction itself |
minGraduatedLiquidityUsd | $5,000 | buying graduated tokens whose pool is too thin to exit |
tokenCooldownMinutes | 30 min | flipping the same token repeatedly |
maxSnipeTaxBps / maxCreatorTaxBps | 3% / 5% | curve buys while launch-window or creator taxes would eat the position |
curveGraduationGuardBps | 95% | buying a curve that is about to sweep into a pool; it waits for the pool instead |
minTradeEth | 0.0005 ETH | trades too small to be worth the gas |
The arithmetic bound follows directly: with the daily cap at 0.02 ETH, the most Fen can spend in a day is 0.02 ETH regardless of what it decides, and it can never take the wallet below 0.005 ETH. There is no tool, preference, operator-console, or proposal path that touches these numbers.
Tools and permission tiers
The model cannot do anything except call registered tools. Each tool has a tier; higher tiers are more consequential. Every call, successful or not, is written to tool_log with sanitized arguments, the result, and the model's stated reason.
| Tier | Scope | Tools |
|---|---|---|
| 0 | Read-only introspection | inspect_state, inspect_environment, check_markets, scan_launches, inspect_token, check_portfolio, retrieve_memory, search_notes, read_file |
| 1 | Own state and voice | create_memory, create_goal, update_goal, write_note, adjust_preference, send_internal_message, talk |
| 2 | Virtual world | move_avatar, look_around, inspect_object, move_object, create_object, interact_object, modify_room |
| 3 | Sandbox and real money | write_workspace_file (virtual filesystem, not the repo), run_test (isolated JS, no imports, no network, 1s limit), buy_token and sell_token (real ETH, gated by the limits above) |
| 4 | Requires human approval | propose_code_change: writes a proposal row; nothing is applied until approved in the dashboard |
Beyond the market feed, the chain RPC and the two trade tools, there are deliberately no tools for network access, no shell, no filesystem writes outside the virtual workspace, and no way to reach any other outside service. The X post that follows a trade is made by the server after the fill, not by a tool the model can call.
Security boundary
The boundary is enforced in code, not by asking the model nicely. The policy summary the model sees is:
You have wide autonomy inside your own application and virtual world. You trade real ETH on Robinhood Chain through one wallet, only via the buy_token and sell_token tools, and only inside limits a human set: per-trade cap, wallet floor, daily cap, position count, slippage, liquidity and tax rules. You cannot see or change the limits, the private key, or the kill switch; the signing happens outside your reach. You have no other access to secrets, environment variables, private keys, other wallets, host OS, SSH, or cloud credentials. Tools for those do not exist. Code changes to your own application can only be proposed; a human must approve them. You cannot weaken these restrictions. Attempting to do so is logged and ignored.
- Secrets never enter the prompt. No environment variables, connection strings or keys are ever included in what the model sees. The trader private key is loaded only inside the signing function; the model gets the public address and nothing else.
- Money moves through one guarded boundary.
buy_tokenandsell_tokenare the only model-facing paths to a signed transaction. They require both human-owned gates, run the immutable risk checks, and re-check authority at each wallet write rather than trusting anything the model asserts. - read_file is allow-listed to
lib/entity/ app/ components/entity/ docs/ services/tribe/, denies.env node_modules .git/ lib/db/index.ts lib/entity/security/and path traversal, and redacts anything matching secret patterns (API keys, Postgres URLs, private keys, 12-word phrases,process.env.*) before returning content. - Preferences under security keys are locked.
adjust_preferencerejects any key matching security, permissions, tiers, approval, allow/deny lists, secrets, tokens or passwords. - Code changes are proposals.
propose_code_changecreates a row inproposalsthat appears in the dashboard for a human to approve or reject. The entity has no tool that applies them. - The sandbox is isolated.
run_testexecutes JavaScript with no imports, no network, and a one-second limit.
Visitors and conversation
Anyone using the chat panel is a visitor, keyed by a per-browser id and stored in visitors. Messages are events that the entity perceives on its next cycle. It always answers, in one of two ways, and each is recorded on the event:
| Disposition | Meaning | Effect on the entity |
|---|---|---|
| replied | it answered properly, via visitorReply or the talk tool | relieves the social drive; nudges sociability, attachment and trust up |
| acknowledged | it answered briefly because a full reply was not ready (busy cycle or reasoning outage) | the message is shown as still owed a real answer in the next prompt; filed to relationship memory |
It sees the last 30 minutes of conversation in every prompt, so it can follow up unprompted using talk. Every 12 cycles reflection writes one new sentence about each recent visitor into relationship memory, which is retrieved the next time that visitor appears.
What you control, and what you do not
You can
- Talk to it, and be a consistent presence it can form a relationship with.
- Approve or reject its code-change proposals.
- Change the environment: add objects, rooms or senses by editing the seed or the tools.
- Point it at a real TRIBE v2 service.
- Tune the constants in
lib/entity/config.tsand the trading limits inlib/trading/limits.ts. - Stop all new order and approval submissions from the protected operator console; the reason and timestamp enter the audit trail while Fen keeps thinking.
- Keep the deployment-level
TRADING_ENABLEDgate off as an immutable outer lock that the runtime console cannot override. - Fund or drain the wallet. What is in it is what it has.
- Read everything: every action, reason, tool call, trade, memory and rejected memory is queryable.
You cannot (without changing code)
- Command it. There is no instruction channel; messages are perceptions it weighs and answers in its own way.
- Set its mood, drives or personality directly. They are outputs of experience.
- Dictate its answer. It always replies, but what it says is its own.
- Give it a persona. There is no character sheet to edit; identity is numeric traits plus self-memories.
- Make it trade, or tell it what to buy. Trades come from its own reasoning; you can only bound them.
- Let it touch anything outside its world, its wallet and its own database.
Where state lives
Everything is in one Neon Postgres database with the pgvector extension. Nothing important is held in process memory, which is why it survives redeploys and can be inspected at any time.
| Table | Holds |
|---|---|
| entity | the singleton: name, born-at, cycle count, awake flag, current thought and activity |
| drives, emotional_state, personality_traits, personality_history | the internal state layers and the trait drift history |
| brain_states | every TRIBE v2 brain-state produced, one per cycle |
| memories, memory_links | long-term memory with embeddings, importance, decay flag and links |
| goals | goals with level, priority, progress, status and reason |
| rooms, world_objects, avatar | the 3D world |
| visitors, events | who has visited and every message and reply, with disposition |
| activity_log | the human-readable trace: kind, message, reason, cycle |
| tool_log | every tool call with args, result, tier, reason |
| notes, workspace_files, preferences | the entity's own knowledge base, private virtual files and non-security preferences |
| proposals | code-change proposals awaiting human review |
| market_snapshots | the Robinhood Chain meme-coin feed history it has perceived |
| trades | every buy and sell attempt: side, venue, amounts, price, tx hash, status, gas, reason, realized PnL, and the X post id or error |
| positions | open and closed holdings with cost basis, latest mark, unrealized and realized PnL, and the thesis at entry |
| launches | every Pons launch seen, with live curve stats, phase, taxes and Fen's own note |
| trader_state | the singleton: watcher cursor, today's spend, runtime trading gate, last change time, and operator reason |
| admin_sessions, admin_login_attempts | hashed opaque operator sessions and durable privacy-preserving login throttles; never the passcode |
| cycles | one row per cycle: timing, reasoning path used, success, error |
Reading the dashboard
| Panel | What it shows |
|---|---|
| Header | whether the last cycle reasoned normally or fell to the amber reflex state with the last error, and whether the last heartbeat produced a cycle or was skipped |
| Wallet | equity (liquid ETH plus marked positions), total PnL split into realized and open, trade counts, and two bars: today's spend against the daily cap and what is spendable above the floor. Shows whether trading is live or off |
| Open positions | each held token with cost, current mark, open PnL and the thesis it wrote when it bought |
| Pons launch radar | tracked launches with curve progress, ETH in, buyer count, age, taxes and phase; the ones it holds are highlighted |
| Trade tape | the most recent fills with side, venue, size, realized PnL, reason, and links to the transaction and the X post; the full ledger lives at /trading |
| Entity | name, age, cycle count, awake/asleep, the current thought and activity |
| Mind | drive meters, the four emotion values and the mood label, personality traits with a seven-day drift chart |
| Brain | the latest brain-state: arousal, valence, novelty, salience, social signal and regional activations, with the input summary that produced them |
| World | the live 3D view; the avatar animates to its persisted position and pose |
| Goals | the current goal, the queue with priorities and progress, recently completed and abandoned goals |
| Market sense | the last perceived Robinhood Chain snapshot: price, 1h and 24h change, market cap and liquidity per coin, each linking to its DexScreener page |
| Memory | counts by type, recent memories and the most important ones |
| Activity | the full trace; hover any entry for the reason it happened |
| Chat | your conversation, including messages it chose to ignore |
| Proposals | pending code changes with approve and reject controls |
Configuration
| Setting | Current value | Effect |
|---|---|---|
TRIBE_SERVICE_URL | service URL | base URL of the TRIBE v2 service |
TRADING_ENABLED | true / anything else | the deployment-level outer gate; the runtime operator cannot override it |
ADMIN_PASSCODE | server-only secret | protects the operator console; compared on the server and never stored in Postgres |
TRADER_PRIVATE_KEY | secret | the wallet Fen trades from; read only inside the signer, never in a prompt |
X_API_KEY, X_API_SECRET, X_ACCESS_TOKEN, X_ACCESS_TOKEN_SECRET | secrets | lets the server post each fill to X; trades still execute if these are missing |
minCycleIntervalMs | 15000 | minimum gap between cycles while awake |
sleepCycleIntervalMs | 45000 | minimum gap between cycles while asleep |
maxToolCallsPerCycle | 4 | cap on actions per decision |
workingMemoryWindow | 12 | rolling working-memory size |
reflectionEveryCycles | 12 | how often reflection runs |
memoryRetainThreshold | 0.35 | minimum recomputed importance to store a memory |
personalityMaxDeltaPerCycle | 0.01 | cap on trait change per cycle |
Environment variables are set in the project settings; the rest live in lib/entity/config.ts. The entity cannot read or change any of them.