How CIAgent agents load project context. The git log IS the project memory — a CIAgent agent's first impulse to gather context is `git log` + `git branch`, not file reads. --- ## Core Principle **Read the log first, files second.** The git log contains every decision, escalation, lesson, and compound learning through structured `---ci---` YAML blocks. Files in `.ciagent/` are long-lived reference documents (PROJECT.md, ARCHITECTURE.md, ROADMAP.md, REQUIREMENTS.md, config.json) that change infrequently. ## Context Loading Sequence 1. **Branch scan** — `GitContext.getBranches()` to discover phase and milestone structure 2. **State reconstruction** — `GitContext.reconstructState()` to get current phase, milestone, stage 3. **Decision scan** — `GitContext.getDecisions()` for all project decisions 4. **Escalation check** — `GitContext.getEscalations()` for any pending escalations 5. **Requirements coverage** — `GitContext.getRequirementsCoverage()` for covered/partial 6. **Lessons scan** — `GitContext.getLessons()` for all learned lessons 7. **Compound learnings** — `GitContext.getCompounds()` for cross-phase patterns 8. **File reads** — Only now read `.ciagent/` files (PROJECT.md, ARCHITECTURE.md, etc.) ## GitContext API | Method | Returns | Purpose | |--------|---------|---------| | `isGitRepo()` | boolean | Check if inside a git repo | | `getCurrentBranch()` | string | Current branch name | | `getRecentCommits(count)` | ParsedCiCommit[] | Recent commits with parsed `---ci---` blocks | | `getLatestCiCommit()` | ParsedCiCommit \| null | Most recent CI commit | | `getBranches()` | BranchInfo[] | All branches with type and merge status | | `getPhaseBranches()` | BranchInfo[] | Phase branches only | | `getMilestoneBranches()` | BranchInfo[] | Milestone branches only | | `reconstructState()` | ProjectState | Full project state from git log | | `getDecisions(phase?)` | CommitDecision[] | Decisions, optionally filtered by phase | | `getLessons(phase?)` | string[] | Learned lessons | | `getCompounds(category?)` | CompoundInfo[] | Compound learnings | | `getEscalations()` | EscalationInfo[] | All escalations | | `getRequirementsCoverage()` | { covered, partial } | Requirement traceability | | `getCommitsForPhase(phase)` | ParsedCiCommit[] | All commits for a phase | | `getCommitsForBranch(branch)` | ParsedCiCommit[] | All commits on a branch | ## ProjectState The `reconstructState()` method returns: ```typescript interface ProjectState { currentPhase: number; currentMilestone: string; currentStage: PipelineStage; phasesCompleted: number[]; phaseBranches: BranchInfo[]; milestoneBranches: string[]; lastCommit: ParsedCiCommit | null; } ``` Derived entirely from git data — no file reads required. ## ParsedCiCommit Every commit returned by `getRecentCommits()` is parsed into: ```typescript interface ParsedCiCommit { hash: string; type: CommitType; scope: string; subject: string; ci: CiMetadata | null; // null if no ---ci--- block body: string; } ``` Commits without `---ci---` blocks have `ci: null` — these are treated as non-CIAgent commits (e.g., manual edits by the developer). ## Phase Context Reset Between phases, all state is committed to git, then the next phase starts with fresh context from git log — not accumulated conversation history. **On opencode (subagent support):** spawn a fresh agent for the next phase. The new agent loads context from git log and `.ciagent/` files only. **On platforms without subagents:** simulated reset — re-read git context from scratch, ignore prior conversation history. Treat the phase boundary as a hard context boundary. **Checkpoint sequence:** 1. Commit all work from the current phase 2. Update `.ciagent/` files (ROADMAP.md phase status, REQUIREMENTS.md requirement statuses) 3. Verify `GitContext.reconstructState()` matches expected state 4. Reset context — next phase begins fresh The phase context reset ensures that each phase operates on verified git state, preventing context drift across long-running projects. ## Multi-Project Context GitContext supports multi-project mode with optional project scoping: | Method | Returns | Purpose | |--------|---------|---------| | `GitContext(projectPath, projectSlug?)` | GitContext | Optional project slug for scoping | | `detectProjectFromCommit()` | string \| null | Detect project from latest commit's `project` field | | `isNfrMilestone()` | boolean | Check if current milestone is NFR-only (no feat phases) | In multi-project mode, `detectProjectFromCommit()` reads the `project` field from the latest `---ci---` block to determine which project context to load. `isNfrMilestone()` inspects phase commit types to determine versioning behavior. ## Context Budget Strategy When context is limited: 1. `reconstructState()` — always (cheap, single call) 2. `getDecisions(currentPhase)` — current phase decisions only 3. `getRequirementsCoverage()` — aggregate view 4. Skip lessons/compounds unless specifically needed 5. Read `.ciagent/ROADMAP.md` instead of scanning all phase branches ## What NOT to Do - Never read `.ciagent/` files before checking the git log - Never parse commit messages manually — use `CommitParser.parseCommitMessage()` - Never assume the latest commit reflects the current state — check branches - Never reconstruct state from files when git data is available - Never skip the branch scan — merged branches indicate completed phases