Files
Mana-Loop/AGENTS.md
T
2026-05-13 12:16:11 +02:00

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:

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:

  1. Pull the latest changes:

    cd /home/user/repos/Mana-Loop && git pull origin master
    
  2. Do your task — Make all necessary code changes

  3. 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:

  1. It must be added as a Filter in OpenWebUI under Workspace → Functions → Filters (NOT under Tools)
  2. It must be toggled ON for the current model or workspace
  3. 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

  1. Mana Gathering — Click or auto-generate mana over time
  2. Studying — Spend mana to learn skills and spells
  3. Combat — Climb the Spire, defeat guardians, sign pacts
  4. Crafting — Enchant equipment with spell effects via 3-step process
  5. 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:

  1. Add to ComputedEffects interface in upgrade-effects.ts
  2. Add mapping in computeEquipmentEffects() in effects.ts
  3. 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.ts
  • crafting-actions/preparation-actions.ts
  • crafting-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() in constants/skills-v2.ts is the authoritative stat calculator

⚠️ Common Pitfalls

  1. Forgetting getUnifiedEffects() — never modify stats directly; use the effect system
  2. Using legacy store — always use stores/ (new), not store/ (legacy)
  3. Not checking circular deps — read docs/circular-deps.txt before modifying shared files
  4. Bypassing crafting-actions — use modular actions for any crafting feature
  5. Using local state for enchantment selection — always use the crafting store
  6. Adding skills to skill-evolution-modules/ — use constants/skills-v2.ts for 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:

  1. File Size Check — no staged file may exceed 400 lines
  2. Project Structure — regenerates docs/project-structure.txt
  3. Dependency Graph — regenerates docs/dependency-graph.json and docs/circular-deps.txt via madge
  4. 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

  1. Define in data/enchantment-effects.ts
  2. Add stat mapping in effects.tscomputeEquipmentEffects()
  3. Apply in game logic using getUnifiedEffects(state)

New Skill

  1. Define in constants/skills-v2.ts (NOT skill-evolution-modules/)
  2. Add to computeStats() effect mapping
  3. UI auto-reads from structure

New Spell

  1. Define in constants/spells.ts
  2. Add enchantment in data/enchantment-effects.ts
  3. Add research skill in constants/skills-v2.ts
  4. 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:

  1. Read:

    • docs/strategy/overall-remediation-plan.md
    • docs/active-task-log.md (if it exists)
    • docs/.workflow/TASK-*.json (any saved progress)
  2. Identify the first roadmap item marked [ ] in the Current Priority table at the top of this file.

  3. If a Work-in-Progress entry exists for that task, resume from the last recorded step. Do not restart.

  4. If no Work-in-Progress entry exists, initialize using the Task Initialization Protocol.

2. Task Initialization Protocol

Before modifying code for a new task:

  1. Update docs/active-task-log.md
  2. Record: task ID, objective, files expected to change, current status, planned tests
  3. Run baseline validation before editing:
    bun run lint && bun run test
    
  4. Record any failing baseline tests before implementation begins
  5. Call save_progress after 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.md updated: [ ][x]
  • docs/active-task-log.md updated (marked ARCHIVED or 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