10 KiB
Executable File
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:
git config --global user.name "n8n-gitea"
git config --global user.email "n8n-gitea@anexim.local"
⚠️ Mandatory Git Workflow
Every session:
# 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:
# 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 typecheckorbun run testif 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 |
⚠️
Editsilently returns""on both success and failure. Always read the file back after editing to confirm the change applied. If it didn't, usewrite_fileinstead.
🏗️ 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:
// 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:
- Add to
ComputedEffectsinterface inupgrade-effects.types.ts - Add mapping in
computeEquipmentEffects()ineffects.ts - Apply in game logic via
getUnifiedEffects(state)
Crafting System (3-Step Enchantment)
Flow: Design → Prepare → Apply
Action modules:
crafting-actions/design-actions.tscrafting-actions/preparation-actions.tscrafting-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 errorsbun 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:
- Define in
data/enchantment-effects.ts - Add stat mapping in
effects.ts→computeEquipmentEffects() - Apply via
getUnifiedEffects(state)
New skill:
- Define in
constants/skills-v2.ts - Add to
computeStats()effect mapping
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