- README.md: title, project name, CLI commands, .ci/ → .ciagent/, ci-files → ciagent-files, CI Modification → CIAgent Modification - AGENTS.md: title, project name, architecture tree, agent count (18→19), test count (25→31 suites, 218→370 tests), version (0.4.0→0.6.0), ci-files → ciagent-files, CIConfig → CIAgentConfig, CiMetadata → CIAgentMetadata, .ci/ → .ciagent/ - templates/DECISIONS.md: .ci/audit/ → .ciagent/audit/, ci audit → ciagent audit - scripts/postinstall.js: CI postinstall → CIAgent postinstall - scripts/install.sh: CI → CIAgent, ci-init → ciagent-init, INSTALL COMPLETE banner - opencode/ci/workflows/*.md (11 files): .ci/ → .ciagent/, CI → CIAgent project name, ci-command → ciagent-command usage lines - opencode/ci/references/*.md (5 files): .ci/ → .ciagent/, CI → CIAgent project name, ci-files → ciagent-files references - opencode/ci/contexts/*.md (3 files): .ci/ → .ciagent/, CI → CIAgent project name - opencode/agents/ci-*.md (18 files): .ci/ → .ciagent/, CI → CIAgent project name - opencode/command/ci-*.md (11 files): CI → CIAgent project name Preserved: ---ci---/---/ci--- markers, opencode/ci/ dir paths, ci-*.md filenames, ci listProjects()/ci setActiveProject() API names, repo URLs ---ci--- phase: 1 milestone: v0.6 plan: 01-01 task: 01-01-01 status: execute ---/ci---
6.3 KiB
<ci_files_discipline>
How CIAgent manages the .ciagent/ directory — long-lived reference documents only. Dynamic state lives in the git log via ---ci--- YAML blocks, not in files.
Multi-Project Directory Structure
In multi-project mode, .ciagent/ uses subdirectories per project:
.ciagent/
config.json # Registry with projects[] and active_project
<project-slug>/
PROJECT.md
ARCHITECTURE.md
ROADMAP.md
REQUIREMENTS.md
.ciagent/config.json serves as the registry with projects[] (array of project entries) and active_project (slug of the currently active project).
Backward compatibility: if .ciagent/ has flat files (PROJECT.md, ARCHITECTURE.md, etc.) and no project subdirectories, auto-migrate by creating <default-slug>/ and moving files into it, then updating config.json with a single projects[] entry.
What Lives in .ciagent/
| File | Purpose | Update Frequency |
|---|---|---|
config.json |
Project registry with projects[] and active_project |
Rare (initialization, project changes) |
<slug>/PROJECT.md |
Vision, core value, requirements, constraints, key decisions per project | Low (phase boundaries) |
<slug>/ARCHITECTURE.md |
System architecture, component boundaries, data flow per project | Low (major refactors) |
<slug>/ROADMAP.md |
Phase breakdown, milestone mapping, success criteria per project | Low (phase transitions) |
<slug>/REQUIREMENTS.md |
v1/v2 requirements with REQ-IDs, out of scope, traceability per project | Low (requirement changes) |
What Does NOT Live in .ciagent/
These were removed in v0.2.0 and now live in the git log:
| Previous Location | Now In | Access Method |
|---|---|---|
.ciagent/audit/decisions.json |
---ci--- decisions block |
GitContext.getDecisions() |
.ciagent/audit/escalations.json |
---ci--- escalations block |
GitContext.getEscalations() |
.ciagent/audit/lessons.json |
---ci--- lessons block |
GitContext.getLessons() |
.planning/ directory (removed) |
Git log + branches | GitContext.reconstructState() |
CiFiles API
| Method | Returns | Purpose |
|---|---|---|
ensureCIDir() |
void | Create .ciagent/ if it doesn't exist |
isInitialized() |
boolean | Check if .ciagent/config.json exists |
readProjectMd() |
ProjectMd | null | Read project definition |
writeProjectMd(project, reason) |
void | Write project definition |
readRoadmapMd() |
RoadmapMd | null | Read roadmap |
writeRoadmapMd(roadmap) |
void | Write roadmap |
readRequirementsMd() |
RequirementsMd | null | Read requirements |
writeRequirementsMd(requirements) |
void | Write requirements |
readArchitectureMd() |
ArchitectureMd | null | Read architecture |
writeArchitectureMd(architecture) |
void | Write architecture |
updateRequirementStatus(reqId, status) |
void | Update a single requirement status |
updatePhaseStatus(phaseNumber, status) |
void | Update a single phase status |
Update Discipline
- Update with reason —
writeProjectMd()takes areasonparameter. Every write must justify why. - Phase boundaries — Major updates happen at phase transitions, not during task execution.
- Requirements status — Use
updateRequirementStatus()for single-status changes, not full rewrites. - Phase status — Use
updatePhaseStatus()for phase transitions, not full roadmap rewrites. - Commit after write — Every
.ciagent/file change should be committed immediately with a---ci---block.
Update Triggers
| When | What to Update | Method |
|---|---|---|
| Project initialization | All files from scratch | write* methods |
| Phase transition | Phase status in ROADMAP.md | updatePhaseStatus() |
| Requirement met | Requirement status in REQUIREMENTS.md | updateRequirementStatus() |
| Architecture change | ARCHITECTURE.md | writeArchitectureMd() |
| Scope change | PROJECT.md | writeProjectMd() |
File Schemas
PROJECT.md
interface ProjectMd {
name: string;
coreValue: string;
requirements: {
validated: string[];
active: string[];
outOfScope: string[];
};
constraints: string[];
context: string;
keyDecisions: Array<{
decision: string;
rationale: string;
outcome: string;
}>;
}
ROADMAP.md
interface RoadmapMd {
overview: string;
phases: Array<{
number: number;
name: string;
description: string;
status: "not_started" | "in_progress" | "complete" | "deferred";
dependsOn: number[];
requirements: string[];
successCriteria: string[];
}>;
}
REQUIREMENTS.md
interface RequirementsMd {
v1: Array<{
category: string;
items: Array<{ id: string; description: string }>;
}>;
v2: Array<{
category: string;
items: Array<{ id: string; description: string }>;
}>;
outOfScope: Array<{ feature: string; reason: string }>;
traceability: Array<{
requirement: string;
phase: number;
status: "pending" | "in_progress" | "complete" | "blocked";
}>;
}
ARCHITECTURE.md
interface ArchitectureMd {
overview: string;
components: Array<{
name: string;
description: string;
boundaries: string;
dependsOn: string[];
}>;
dataFlow: string;
buildOrder: string[];
}
Research and .ci/ File Updates
Research is intermediate work product. Conclusions from research update .ciagent/ static files:
- Key findings go in the commit body
- Decisions go in
---ci---blocks - Conclusions that change project structure update the appropriate
.ciagent/<slug>/files (ARCHITECTURE.md, PROJECT.md, etc.)
Research commits are not final artifacts — they feed into planning and roadmap updates.
Anti-Patterns
- Never write dynamic state (decisions, escalations, lessons) to
.ciagent/files - Never update
.ciagent/files during task execution — update at phase boundaries - Never skip the
reasonparameter when writing PROJECT.md - Never commit
.ciagent/changes without a---ci---block - Never create new files in
.ciagent/without updating this reference document - Never store counters, timestamps, or session state in
.ciagent/files - Never store research conclusions only in commits — update
.ciagent/<slug>/static files with findings
</ci_files_discipline>