# Mana Loop — Agent Guide **Mana Loop** is a browser-based incremental/idle game. Pure client-side Next.js + Zustand — no backend, no database, no server state. --- ## 🔑 Git Credentials **HTTPS URL with credentials:** ``` https://n8n-gitea:tkF9HFgxL2k4cmT@gitea.tailf367e3.ts.net/Anexim/Mana-Loop.git ``` **Configure once per session:** ```bash git config --global user.name "n8n-gitea" git config --global user.email "n8n-gitea@anexim.local" ``` --- ## ⚠️ Mandatory Git Workflow Every session: ```bash # Start cd /home/user/repos/Mana-Loop && git pull origin master # Finish git add -A git commit -m "type: short description" git push origin master ``` No exceptions. Always pull first, always push when done. --- ## 🗂️ Gitea Is The Source Of Truth All task state lives in Gitea issues. No markdown files track status — the issue label and comments are the record. **Gitea URL:** `https://gitea.tailf367e3.ts.net/Anexim/Mana-Loop` **Labels:** | Label | Meaning | |---|---| | `ai:todo` | Not started | | `ai:in-progress` | Being worked on now | | `ai:review` | Done, needs human review | | `ai:blocked` | Stuck — comment explains why | | `ai:done` | Complete, issue closed | ### Session Start Protocol ``` 1. Read docs/project-structure.txt ← mandatory, every session 2. Read docs/dependency-graph.json ← mandatory, every session 3. Call get_repo_summary → see what's in-progress, blocked, todo 4. If an issue is in-progress → call get_issue_context on it and resume 5. If nothing in-progress → pick the highest-priority todo 6. Call update_issue_status → move it to "in-progress" 7. Work on it 8. Log significant steps with add_comment 9. When done → update_issue_status to "done" (closes the issue) ``` Steps 1 and 2 are non-negotiable even if you think you know the codebase. `project-structure.txt` tells you exactly where files live so you don't waste tool calls searching. `dependency-graph.json` tells you the blast radius of any change before you make it — who imports what, so you never edit a shared file blind. **How to use `dependency-graph.json`:** ```bash # What files will break if I touch stores/skillStore.ts? node -e " const d = require('./docs/dependency-graph.json').graph; const target = 'stores/skillStore.ts'; Object.entries(d) .filter(([,deps]) => deps.some(dep => dep.includes(target))) .forEach(([f]) => console.log(f)); " # What does a file depend on? 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)); " ``` ### Progress Logging Use `add_comment` on the issue to log what you did. A good comment includes: - What was changed and why - Any errors encountered and how they were resolved - Exact files modified - Output of `bun run typecheck` or `bun run test` if relevant If you stop mid-task for any reason, leave a comment with `STATUS: STOPPED` so the next session knows exactly where to resume. --- ## ⚙️ Terminal Tool Protocol — READ THIS The terminal tool is **async**. `run_command` starts a process and returns immediately with `status: "running"`. You **must** follow up with `get_process_status` in the same response turn. **Correct pattern — always do this:** ``` run_command({ command: "cd /home/user/repos/Mana-Loop && bun run typecheck" }) → { status: "running", id: "abc123" } [IMMEDIATELY call — do NOT stop here] get_process_status({ process_id: "abc123", wait: 60 }) → { status: "done", output: [...] } ``` **Never** end your response after seeing `status: "running"`. Always call `get_process_status` in the same turn. If you hit output length limits, the user will say "continue" and you pick up from `get_process_status`. For long-running commands (full tsc, test suite), use `wait: 120`. --- ## 🤖 Sub-Agent Usage Use `run_sub_agent` when a task needs 3+ sequential tool calls that don't depend on the main conversation (file reading, grep investigations, isolated fixes). **Key rule:** Sub-agents have zero context from the parent conversation. Paste everything they need directly into the `prompt` field — file contents, task description, constraints, expected output format. **When to use sub-agents:** - Investigating what files access a given function/type - Running a fix + typecheck + commit as an isolated unit - Parallel context gathering (use `run_parallel_sub_agents`) **When NOT to use sub-agents:** - Simple single-file reads — just read the file directly - Tasks that need the result of a prior tool call from this session --- ## 🛠️ Tools Available | Tool | When to use | |------|-------------| | `get_repo_summary` | Session start — see all open issues by state | | `get_issue_context` | Resuming — read issue body + all comments | | `update_issue_status` | Move issue through workflow, optionally add comment | | `add_comment` | Log progress, errors, decisions on an issue | | `create_issue` | Found a new bug or task that warrants its own issue | | `run_sub_agent` | Delegate isolated investigation or fix | | `run_parallel_sub_agents` | Parallel independent investigations | | `ask_advisor` | Second opinion before a refactor or architectural decision | | `run_command` + `get_process_status` | Terminal commands (always pair these) | | `read_file` | Read a file | | `write_file` | Write a file (prefer over Edit for whole-file rewrites) | | `Edit` | Targeted in-file edits — **always verify with `read_file` after** | > ⚠️ `Edit` silently returns `""` on both success and failure. Always read the file back after editing to confirm the change applied. If it didn't, use `write_file` instead. --- ## 🏗️ Project Architecture ### Stack - **Framework:** Next.js 16, App Router - **Language:** TypeScript 5 - **Styling:** Tailwind CSS 4 + shadcn/ui - **State:** Zustand with persist middleware — **all game state lives here, no backend** - **Tests:** Vitest (unit), Playwright (E2E) - **Package manager:** Bun ### Key Directories ``` src/lib/game/stores/ ← ✅ Active Zustand store modules (USE THESE) src/lib/game/crafting-actions/ ← Modular crafting actions src/lib/game/constants/ ← Game data (guardians, spells, skills, elements) src/lib/game/types/ ← TypeScript interfaces src/lib/game/utils/ ← Pure utility functions src/lib/game/store/ ← ⚠️ Legacy store slices (migration in progress) src/lib/game/store-modules/ ← ⚠️ Legacy modules (being replaced) src/components/game/ ← All UI components e2e/ ← Playwright E2E tests ``` ### Store Map | Store | File | Owns | |-------|------|------| | Game | `stores/gameStore.ts` | Core state, tick loop, equip/unequip | | Mana | `stores/manaStore.ts` | Raw mana, elements, conversion | | Combat | `stores/combatStore.ts` | Spire, spells, floor progression | | Prestige | `stores/prestigeStore.ts` | Insight, upgrades, loop end | | Skill | `stores/skillStore.ts` | Skill levels, studying | | UI | `stores/uiStore.ts` | Modal state, debug flags | Cross-store reads: ```typescript // In combatStore.ts reading mana state: const manaState = useManaStore.getState(); ``` ### Effect System — Critical All stat modifications flow through `getUnifiedEffects(state)` in `effects.ts`. **Never read skill levels directly to compute a stat.** Always use the unified effects object. Adding a new stat: 1. Add to `ComputedEffects` interface in `upgrade-effects.types.ts` 2. Add mapping in `computeEquipmentEffects()` in `effects.ts` 3. Apply in game logic via `getUnifiedEffects(state)` ### Crafting System (3-Step Enchantment) Flow: **Design → Prepare → Apply** Action modules: - `crafting-actions/design-actions.ts` - `crafting-actions/preparation-actions.ts` - `crafting-actions/application-actions.ts` The crafting store is the **single source of truth** for enchantment selection state. Never use local component state for selected effects. ### Skill System (v2) New skills: define in `constants/skills-v2.ts`, add to `computeStats()`. Old skills: still in `skill-evolution-modules/` — migration ongoing. Never add new skills to `skill-evolution-modules/`. --- ## 🔍 Impact Analysis (Before Editing Shared Files) Before modifying any file imported by 3+ other files, check the dependency graph you read at session start. If 5+ files import it, or it's in a circular chain (check `docs/circular-deps.txt`), use `ask_advisor` with `advisor_type: "review"` before touching it. --- ## ✅ Definition of Done A task is complete only when ALL of these are true: - [ ] Implementation done - [ ] `bun run typecheck` — 0 errors - [ ] `bun run lint` — 0 errors - [ ] Relevant tests pass (`bun run test`) - [ ] New tests added for any bug fix or new system - [ ] Changes committed and pushed - [ ] Gitea issue updated to `ai:done` (closes the issue) --- ## 🚫 Banned — Never Add These - **Lifesteal / healing mechanics** — player cannot take damage - **Scroll crafting** — violates NO INSTANT FINISHING design pillar - **Ascension skills** — deleted - **LabTab** — permanently removed, do not re-add under any name - **Pause button** — does not exist - **Mana types:** `life`, `blood`, `wood`, `mental`, `force` — banned --- ## 📐 File Size **400 lines maximum** per file — enforced by pre-commit hook. If a file approaches this, split it before the hook rejects the commit. --- ## 🔮 Mana Types Reference **Base (7):** Fire 🔥, Water 💧, Air 🌬️, Earth ⛰️, Light ☀️, Dark 🌑, Death 💀 **Utility (1):** Transference 🔗 **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 --- ## ⚡ Quick Reference — Adding Things **New effect:** 1. Define in `data/enchantment-effects.ts` 2. Add stat mapping in `effects.ts` → `computeEquipmentEffects()` 3. Apply via `getUnifiedEffects(state)` **New skill:** 1. Define in `constants/skills-v2.ts` 2. Add to `computeStats()` effect mapping **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`