21 KiB
Executable File
Mana Loop — Project Architecture Guide for AI Agents
This document provides everything an AI agent needs to work on this codebase safely and effectively. Read it in full before writing a single line of code.
⚠️ TERMINAL TOOL PROTOCOL
After calling run_command, you MUST immediately call get_process_status
with wait: 30 in the SAME response. Never stop generating after a
status: "running" result — always follow up immediately.
After ANY Edit tool call, immediately call read_file to verify the change is present. If it's not, use write_file instead.
🔑 Git Credentials (SAVE THESE)
Repository: git@gitea.tailf367e3.ts.net:Anexim/Mana-Loop.git
HTTPS URL with credentials:
https://n8n-gitea:tkF9HFgxL2k4cmT@gitea.tailf367e3.ts.net/Anexim/Mana-Loop.git
Credentials:
- User: n8n-gitea
- Email: n8n-gitea@anexim.local
- Password: tkF9HFgxL2k4cmT
To configure git:
git config --global user.name "n8n-gitea"
git config --global user.email "n8n-gitea@anexim.local"
⚠️ MANDATORY GIT WORKFLOW — MUST BE FOLLOWED
Before starting ANY work, you MUST:
-
Pull the latest changes:
cd /home/user/repos/Mana-Loop && git pull origin master -
Do your task — Make all necessary code changes
-
Before finishing, commit and push:
cd /home/user/repos/Mana-Loop git add -A git commit -m "descriptive message about changes" git push origin master
This workflow is enforced and non-negotiable. Every session must start with git pull and end with git push.
🎯 CURRENT PRIORITY — READ THIS FIRST
Every session must start by reading the active strategy document to know what to work on:
cat docs/strategy/overall-remediation-plan.md
The strategy defines the current phase and task queue. Do not pick tasks on your own. Always work on the highest-priority incomplete task from the strategy.
Current active task queue (update this when the strategy changes):
| # | Task | Status |
|---|---|---|
| TASK-001 | Playwright setup + baseline E2E tests | ⬜ |
| TASK-002 | Enchanting E2E tests (3-step flow) | ⬜ |
| TASK-003 | Equipment E2E tests (equip, 2H block, unequip) | ⬜ |
| TASK-004 | Combat E2E tests (cast, HP, floor advance) | ⬜ |
| TASK-005 | globals.css design tokens |
⬜ |
| TASK-006 | Left panel redesign | ⬜ |
| TASK-007 | Skill system v2 (computeStats + migration) |
⬜ |
| TASK-008 | Enchanting UI fix (store as source of truth) | ⬜ |
| TASK-009 | Attunement expansion (new attunements + path choice) | ⬜ |
| TASK-010 | Prestige rework (path bonuses) | ⬜ |
| TASK-011 | Full UI redesign (remaining tabs) | ⬜ |
🔄 Crash Recovery Protocol
If the agent's session ends mid-task, a fresh session must resume from where it left off, not restart.
Saving progress (MANDATORY after every significant step):
Call save_progress with:
task_id: "TASK-XXX-task-name"
status: "in_progress"
completed_steps: ["step 1 description", "step 2 description"]
next_step: "what to do next"
notes: "any context for the next session"
project_path: "/home/user/repos/Mana-Loop"
On session start — check for existing progress:
cat docs/.workflow/TASK-XXX-task-name.json 2>/dev/null
If a Work-in-Progress entry exists in the active-task-log:
- Resume from the last recorded step. Do not restart the task.
- Read the saved notes to understand context.
If no Work-in-Progress entry exists:
- Initialize the task using the Task Initialization Protocol below.
📖 MANDATORY CONTEXT FILES — READ BEFORE EVERY TASK
You must read these files at the start of every session before writing any code:
# 1. Auto-generated project file tree
cat docs/project-structure.txt
# 2. Module dependency graph — who imports whom
cat docs/dependency-graph.json
# 3. Circular dependency report — red alert if non-empty
cat docs/circular-deps.txt
# 4. The strategy document (active priorities)
cat docs/strategy/overall-remediation-plan.md
# 5. Any existing progress checkpoint for current task
cat docs/.workflow/TASK-*.json 2>/dev/null
How to use docs/dependency-graph.json
The graph is a JSON object where keys are files and values are arrays of files they import.
To find the blast radius of changing a file (what will break):
node -e "
const d = require('./docs/dependency-graph.json').graph;
const target = 'stores/skillStore.ts';
const affected = Object.entries(d).filter(([,deps]) => deps.some(dep => dep.includes(target)));
affected.forEach(([f]) => console.log(f));
"
To find what a file depends on (its imports):
node -e "
const d = require('./docs/dependency-graph.json').graph;
const key = Object.keys(d).find(k => k.includes('skillStore'));
console.log(JSON.stringify(d[key], null, 2));
"
How to use docs/circular-deps.txt
If this file contains anything other than "No circular dependencies found", stop and fix the circulars before touching any of the involved files. Circular imports are the #1 cause of silent runtime failures in this codebase.
When to re-generate the dependency graph manually
The graph is auto-generated on commit via husky, but if you need fresh data mid-session:
node .husky/scripts/generate-dependency-graph.js
🧰 AVAILABLE TOOLS IN THIS ENVIRONMENT
The following OpenWebUI tools are available in this agent session. Use them — they exist to make your work safer and faster.
1. Sub Agent (run_sub_agent, run_parallel_sub_agents)
What it does: Delegates a tool-heavy task to a fresh isolated context. The sub-agent runs its own tool loop and returns only the final result, keeping the main conversation context clean.
When to use it:
- Any investigation that requires 3+ sequential tool calls (file reads, git operations, analysis)
- Parallel research tasks that don't depend on each other
- Heavy grep/search operations that would pollute the main context
How to invoke:
Call run_sub_agent with:
description: "Brief task summary shown as status"
prompt: "Full detailed instructions — include ALL context the sub-agent needs,
it has NO access to this conversation history"
Critical: The sub-agent starts with zero context. Paste the relevant file contents, task spec, and constraints directly into the prompt field. Do not assume it knows anything.
Parallel tasks:
Call run_parallel_sub_agents with:
tasks: [
{ description: "...", prompt: "..." },
{ description: "...", prompt: "..." }
]
Use this when tasks are independent (e.g. investigating combat while also reading skill files).
2. Dev Workflow Pro (save_progress, run_checks)
What it does: Runs quality checks (typecheck, lint, test) from within the agent session, and saves task progress as JSON checkpoints in docs/.workflow/.
⚠️ Configuration required: The project_path valve must be set to /home/user/repos/Mana-Loop for this tool to work. If it returns "Project path is missing", the valve isn't configured — fall back to run_sub_agent with a shell command.
Verify it works:
Call run_checks with:
checks: ["lint"]
project_path: "/home/user/repos/Mana-Loop"
If this returns ✅ lint output, it's working. If it errors, use the sub-agent fallback below.
Sub-agent fallback (always works):
Call run_sub_agent with:
description: "Run lint and typecheck"
prompt: "cd /home/user/repos/Mana-Loop && bun run lint && bun run typecheck.
Return the full output including any errors."
Saving progress between sessions:
Call save_progress with:
task_id: "TASK-001-playwright-setup"
status: "in_progress"
completed_steps: ["installed playwright", "configured playwright.config.ts"]
next_step: "write first E2E test for enchanting flow"
notes: "need to verify test:ui script works before writing tests"
project_path: "/home/user/repos/Mana-Loop"
Progress is saved to docs/.workflow/TASK-001-playwright-setup.json. Read it at the start of a resumed task.
3. Advisor (ask_advisor, debate)
What it does: Calls a specialist LLM in complete isolation to get a second opinion before making a decision. Zero context pollution — only your question and the context you paste reaches it.
When to use it — this is mandatory for:
- Splitting or refactoring any file → use
advisor_type: "refactor" - Any new game mechanic that touches more than 2 systems → use
advisor_type: "code" - Design decisions that could affect balance or lore → use
advisor_type: "lore" - Before committing a significant implementation → use
advisor_type: "review"
Advisor types:
| Type | When to use |
|---|---|
refactor |
Before splitting any file. Paste the FULL file content in context. |
code |
TypeScript / React / Zustand / game architecture decisions |
lore |
Game mechanic consistency, attunement balance, prestige design |
review |
Bug-finding pass on a plan or code snippet before committing |
challenge |
Argues AGAINST your approach — run before major architectural decisions |
general |
Anything else |
Example — checking a refactor plan:
Call ask_advisor with:
question: "I want to split skillStore.ts into skillStore.ts and skillEvolution.ts.
Is this safe? What are the circular import risks?"
advisor_type: "refactor"
context: "[paste the full skillStore.ts content here]"
4. Game Dev Agent Skills (Inlet Filter)
What it does: Automatically injects engineering skill workflows (spec, TDD, debug, refactor, perf, review, security) into the system prompt based on keywords in your message.
⚠️ This is a Filter, not a Tool — it requires specific setup to work:
- It must be added as a Filter in OpenWebUI under Workspace → Functions → Filters (NOT under Tools)
- It must be toggled ON for the current model or workspace
- Keyword detection is automatic — the workflow injects based on what words appear in the user's message
Trigger keywords:
| Skill | Keywords that activate it |
|---|---|
spec |
spec, specifications, prd, scope, requirements |
debug |
bug, error, crash, broken, fix, not working |
plan |
plan, breakdown, tasks, todo, roadmap, milestone |
implement |
implement, build, write, create, add feature |
tdd |
test, tdd, unit test, failing test, coverage, vitest |
perf |
slow, lag, fps, frame time, memory leak, optimise |
review |
review, code quality, refactor, clean up, PR |
security |
auth, login, token, exploit, injection, hack |
If it's not injecting: Check that it's installed as a Filter (not a Tool) and is enabled for the active model. In forced mode, set the forced_skill valve to the skill you want instead of "auto".
🔴 BEFORE EDITING ANY FILE — Impact Analysis Protocol
Before modifying a function, store, or component, always answer these questions:
# 1. Who imports this file?
node -e "
const d = require('./docs/dependency-graph.json').graph;
const me = 'stores/skillStore.ts'; // change this
Object.entries(d).filter(([,v]) => v.some(dep => dep.includes(me)))
.forEach(([f]) => console.log('imports me:', f));
"
# 2. Are there circular deps involving this file?
grep -i "skillStore" docs/circular-deps.txt
# 3. What tests cover this file?
find src -name "*.test.ts" | xargs grep -l "skillStore" 2>/dev/null
If the impact is HIGH (5+ files import it, or it's in a circular chain) — call the Advisor with advisor_type: "review" or advisor_type: "challenge" before making changes.
🗂️ Project Overview
Mana Loop is a browser-based incremental/idle game built with:
- Framework: Next.js 16 with App Router
- Language: TypeScript 5
- Styling: Tailwind CSS 4 with shadcn/ui components
- State Management: Zustand with persist middleware (modular store architecture)
- Database: Prisma ORM with SQLite
- Test Runner: Vitest
- Package Manager: Bun
Core Game Loop
- Mana Gathering — Click or auto-generate mana over time
- Studying — Spend mana to learn skills and spells
- Combat — Climb the Spire, defeat guardians, sign pacts
- Crafting — Enchant equipment with spell effects via 3-step process
- Prestige — Reset progress for permanent bonuses (Insight)
Directory Structure
See docs/project-structure.txt for the full auto-generated tree. The key directories:
src/lib/game/stores/ # ✅ USE THESE — Zustand store modules
src/lib/game/crafting-actions/ # Modular crafting system
src/lib/game/data/ # Game data definitions
src/lib/game/constants/ # Game constants by domain
src/lib/game/utils/ # Utility functions
src/lib/game/store/ # ⚠️ LEGACY — migration in progress
src/lib/game/store-modules/ # ⚠️ LEGACY — being migrated to utils/
src/lib/game/skill-evolution-modules/ # ⚠️ LEGACY — being replaced by computeStats()
src/components/game/ # All game UI components (modular structure)
src/lib/game/stores/__tests__/ # Store-level unit tests
e2e/ # Playwright E2E tests (added in Phase 0)
Key Systems
State Management
| Store | File | Responsibility |
|---|---|---|
| Game Store | stores/gameStore.ts |
Core state, tick loop, equip/unequip |
| Mana Store | stores/manaStore.ts |
Raw mana, elements, conversion |
| Combat Store | stores/combatStore.ts |
Spire, spells, floor progression |
| Prestige Store | stores/prestigeStore.ts |
Insight, upgrades, loop end |
| Skill Store | stores/skillStore.ts |
Skill levels, studying |
| UI Store | stores/uiStore.ts |
Modal state, debug flags |
Cross-store access pattern:
// In combatStore.ts, reading mana state:
const manaState = useManaStore.getState();
Effect System (effects.ts) — CRITICAL
All stat modifications flow through getUnifiedEffects(state). Never read skill levels directly to compute a stat — always use the unified effects object.
When adding a new stat:
- Add to
ComputedEffectsinterface inupgrade-effects.ts - Add mapping in
computeEquipmentEffects()ineffects.ts - Apply in the relevant game logic using
getUnifiedEffects(state)
Crafting System (3-Step Enchantment)
The enchantment flow is Design → Prepare → Apply. Each step is in its own action module:
crafting-actions/design-actions.tscrafting-actions/preparation-actions.tscrafting-actions/application-actions.ts
The store is the single source of truth for enchantment selection state — never use local component state for selected effects.
Skill System (v2 — computeStats())
The old skill-evolution-modules/ system is being replaced by a flat computeStats() function (see strategy doc Phase 1). Until migration is complete:
- Old skills still exist in
skill-evolution-modules/ - New skills will be defined in
constants/skills-v2.ts computeStats()inconstants/skills-v2.tsis the authoritative stat calculator
⚠️ Common Pitfalls
- Forgetting
getUnifiedEffects()— never modify stats directly; use the effect system - Using legacy store — always use
stores/(new), notstore/(legacy) - Not checking circular deps — read
docs/circular-deps.txtbefore modifying shared files - Bypassing crafting-actions — use modular actions for any crafting feature
- Using local state for enchantment selection — always use the crafting store
- Adding skills to
skill-evolution-modules/— useconstants/skills-v2.tsfor new skills
🧪 Testing Priorities
Tests are non-negotiable. Run npm run test before every commit. All tests must pass.
Priority order (if time is short, protect these first):
| Priority | Test Type | What |
|---|---|---|
| 🔴 Critical | E2E | Enchantment flow (Design → Prepare → Apply) |
| 🔴 Critical | E2E | Gear equipping + 2H weapon blocking |
| 🔴 Critical | E2E | Combat tick and floor advancement |
| 🟡 High | E2E | Locked effects cannot be selected |
| 🟡 High | Unit | Store actions that modify rawMana |
| 🟡 High | Unit | Store actions that modify equippedInstances |
| 🟡 High | Unit | computeStats() returns correct values per skill level |
| 🟢 Medium | Unit | computeRegen, computeMaxMana, calcDamage |
| 🟢 Medium | Unit | canAffordSpellCost, spendRawMana, deductSpellCost |
When fixing a bug: write the failing test FIRST, then fix until it passes.
Test locations:
- E2E:
e2e/*.spec.ts - Store tests:
src/lib/game/stores/__tests__/ - Store-level tests:
src/lib/game/store-tests/ - Split tests:
src/lib/game/stores-split-tests/
Git Hooks (Husky)
Pre-Commit Hook (.husky/pre-commit)
Runs automatically before each commit:
- File Size Check — no staged file may exceed 400 lines
- Project Structure — regenerates
docs/project-structure.txt - Dependency Graph — regenerates
docs/dependency-graph.jsonanddocs/circular-deps.txtvia madge - Auto-stages all generated docs files
Post-Merge Hook (.husky/post-merge)
Runs after merge — auto-installs if package.json changed.
Madge Setup
If docs/dependency-graph.json is missing or stale, install madge and regenerate:
bun add -d madge
node .husky/scripts/generate-dependency-graph.js
File Size Guidelines
400 lines maximum per file (enforced by pre-commit hook).
| Directory | Purpose | Target |
|---|---|---|
stores/ |
Zustand store modules | < 400 lines |
crafting-actions/ |
Crafting system actions | < 400 lines |
constants/ |
Game constants by domain | < 400 lines |
data/ |
Game data definitions | < 400 lines |
components/game/tabs/ |
UI tab components | < 400 lines |
🚫 Banned Content
Never Add These
- Lifesteal / Healing mechanics — the player cannot take damage. Healing is unnecessary.
- Scroll Crafting — violates NO INSTANT FINISHING design pillar.
- Ascension Skills — deleted.
Banned Mana Types
Never re-add: life, blood, wood, mental, force
Removed Features
- LabTab — permanently removed. Do not re-add under any name.
- Pause button — does not exist. Do not add one.
🔮 Mana Types Reference
Base (7)
| Element | Symbol | Color |
|---|---|---|
| Fire | 🔥 | #FF6B35 |
| Water | 💧 | #4ECDC4 |
| Air | 🌬️ | #00D4FF |
| Earth | ⛰️ | #F4A261 |
| Light | ☀️ | #FFD700 |
| Dark | 🌑 | #9B59B6 |
| Death | 💀 | #778CA3 |
Utility (1)
| Element | Symbol | Color |
|---|---|---|
| Transference | 🔗 | #1ABC9C |
Compound (3) — Fire+Earth=Metal, Earth+Water=Sand, Fire+Air=Lightning
Exotic (3) — Sand+Sand+Light=Crystal, Fire+Fire+Light=Stellar, Dark+Dark+Death=Void
Adding New Things — Quick Reference
New Effect
- Define in
data/enchantment-effects.ts - Add stat mapping in
effects.ts→computeEquipmentEffects() - Apply in game logic using
getUnifiedEffects(state)
New Skill
- Define in
constants/skills-v2.ts(NOTskill-evolution-modules/) - Add to
computeStats()effect mapping - UI auto-reads from structure
New Spell
- Define in
constants/spells.ts - Add enchantment in
data/enchantment-effects.ts - Add research skill in
constants/skills-v2.ts - Map research to effect in
EFFECT_RESEARCH_MAPPING
🔄 Agent Operational Protocol
1. State & Resumption Protocol
Before starting any implementation work, determine the current project state:
-
Read:
docs/strategy/overall-remediation-plan.mddocs/active-task-log.md(if it exists)docs/.workflow/TASK-*.json(any saved progress)
-
Identify the first roadmap item marked
[ ]in the Current Priority table at the top of this file. -
If a Work-in-Progress entry exists for that task, resume from the last recorded step. Do not restart.
-
If no Work-in-Progress entry exists, initialize using the Task Initialization Protocol.
2. Task Initialization Protocol
Before modifying code for a new task:
- Update
docs/active-task-log.md - Record: task ID, objective, files expected to change, current status, planned tests
- Run baseline validation before editing:
bun run lint && bun run test - Record any failing baseline tests before implementation begins
- Call
save_progressafter completing each significant step
3. Definition of Done
A task is only complete when ALL of the following are true:
- Implementation is complete
- Lint passes
- All relevant tests pass (see Testing Priorities above)
- New tests added for bug fixes or new systems
docs/strategy/overall-remediation-plan.mdupdated:[ ]→[x]docs/active-task-log.mdupdated (markedARCHIVEDor cleared)- Changes committed and pushed:
git add -A git commit -m "feat: [task] — [summary]" git push origin master
4. Roadmap Execution Rules
- Work on ONE roadmap task at a time unless explicitly told otherwise
- Do not perform unrelated refactors
- Do not expand scope beyond current task acceptance criteria
- Large redesigns → split into
docs/tasks/ - Every task maps back to a strategy item