Files
ci/opencode/ci/references/git-context-loading.md
T
CI cf5e7695fd feat(P03): multi-project support, NFR milestone versioning, phase context reset, install scripts
---ci---
phase: 3
milestone: v0.3.0
status: complete
decisions:
  - id: D-006
    decision: Multi-project via .ci/<slug>/ subdirectories and config.json registry
    rationale: Backward compatible migration from flat files; slug-based namespacing for branches and commits
    confidence: 0.92
    alternatives: [Git worktrees, Separate repos with subtrees]
  - id: D-007
    decision: NFR milestones use progressive patch versioning (no minor tag)
    rationale: NFR phases (fix/chore/docs/perf/refactor/test) don't represent feature delivery; patch increments reflect incremental improvement only
    confidence: 0.90
    alternatives: [Treat all milestones uniformly, Skip versioning for NFR]
  - id: D-008
    decision: Phase context reset via git checkpoint + fresh agent spawn
    rationale: Git-native architecture makes full state serialization safe; fresh context prevents accumulated conversation drift
    confidence: 0.88
    alternatives: [Context compaction, Sliding window summarization]
  - id: D-009
    decision: Install via both npm postinstall and standalone bash script
    rationale: Postinstall only fires on npm install -g; standalone script covers manual/cloned installs
    confidence: 0.95
    alternatives: [Postinstall only, Makefile target]
---/ci---

Source code:
- Added ProjectEntry, projects[], active_project to CIConfig
- Added project?: string to CiMetadata, CommitScope, all commit input types
- CiFiles: multi-project support (projectSlug, listProjects, addProject, migrateFlatToProject, isNfrMilestone)
- GitContext: projectSlug support, detectProjectFromCommit(), isNfrMilestone()
- GitBranch: project-prefixed branch naming via prefix()
- commit-builder/parser: project field in ---ci--- blocks
- config.ts: initCI() accepts projectSlug/projectName
- Implemented parseRoadmapMd phase parsing
- 284 tests passing (66 new tests)

Install scripts:
- scripts/install.sh: Standalone bash installer
- scripts/postinstall.js: npm postinstall (global installs only)

OpenCode integration:
- All 18 agents updated with multi-project project_context
- All 11 workflows updated with Step 0: Confirm Active Project
- All 5 references updated (branch-strategy, ci-files-discipline, commit-schema, decision-engine, git-context-loading)
- All 3 contexts updated (dev, research, review)
- VERSION bumped to 0.3.0

Package:
- Added files field, postinstall script, install script alias
- Version bumped to 0.3.0
2026-05-29 14:11:49 +00:00

5.4 KiB

<git_context_loading>

How CI agents load project context. The git log IS the project memory — a CI 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 .ci/ are long-lived reference documents (PROJECT.md, ARCHITECTURE.md, ROADMAP.md, REQUIREMENTS.md, config.json) that change infrequently.

Context Loading Sequence

  1. Branch scanGitContext.getBranches() to discover phase and milestone structure
  2. State reconstructionGitContext.reconstructState() to get current phase, milestone, stage
  3. Decision scanGitContext.getDecisions() for all project decisions
  4. Escalation checkGitContext.getEscalations() for any pending escalations
  5. Requirements coverageGitContext.getRequirementsCoverage() for covered/partial
  6. Lessons scanGitContext.getLessons() for all learned lessons
  7. Compound learningsGitContext.getCompounds() for cross-phase patterns
  8. File reads — Only now read .ci/ 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:

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:

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-CI 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 .ci/ 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 .ci/ 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 .ci/ROADMAP.md instead of scanning all phase branches

What NOT to Do

  • Never read .ci/ 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

</git_context_loading>