feat(context): inject CLAUDE.md / AGENTS.md as L0 standing context
On session start, discover CLAUDE.md and AGENTS.md at the bound workspace root and inject their (concatenated, header-labeled) contents as an L0 system context entry for every stage — mirroring the .correx/project.toml ProjectProfile path end to end. Recorded as AgentInstructionsBoundEvent (invariant #9) so replay reads the recorded fact, not the live file; folded into SessionState.boundAgentInstructions and rendered by buildAgentInstructionsEntry right after the project profile. AgentInstructionsLoader reads root-only, both files if present. Bound via ServerModule.bindAgentInstructions alongside bindProjectProfile. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,11 @@ import com.correx.core.approvals.ApprovalProjector
|
||||
import com.correx.core.approvals.DefaultApprovalReducer
|
||||
import com.correx.core.approvals.DefaultApprovalRepository
|
||||
import com.correx.core.artifactstore.ArtifactStore
|
||||
import com.correx.core.config.AgentInstructionsLoader
|
||||
import com.correx.core.config.OperatorProfile
|
||||
import com.correx.core.config.ProjectProfileLoader
|
||||
import com.correx.apps.server.memory.ArchitectContradictionChecker
|
||||
import com.correx.core.events.events.AgentInstructionsBoundEvent
|
||||
import com.correx.core.events.events.ApprovalRequestedEvent
|
||||
import com.correx.core.events.events.ArtifactContentStoredEvent
|
||||
import com.correx.core.events.events.ArtifactCreatedEvent
|
||||
@@ -322,6 +324,7 @@ class ServerModule(
|
||||
)
|
||||
}
|
||||
bindProjectProfile(sessionId)
|
||||
bindAgentInstructions(sessionId)
|
||||
runCatching {
|
||||
val result = orchestrator.run(sessionId, graph, sessionConfig)
|
||||
freestyleHandoff(sessionId, graph, result)
|
||||
@@ -405,6 +408,37 @@ class ServerModule(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind standing agent instructions (CLAUDE.md / AGENTS.md at the workspace root) as an
|
||||
* event so stages, router chat triage, and replay read the recorded snapshot, never the
|
||||
* live file (invariants #8/#9). Mirrors [bindProjectProfile].
|
||||
*/
|
||||
suspend fun bindAgentInstructions(sessionId: SessionId) {
|
||||
val workspaceRoot = runCatching {
|
||||
sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot
|
||||
}.getOrNull() ?: projectMemory?.repoRoot() ?: return
|
||||
val instructions = withContext(Dispatchers.IO) { AgentInstructionsLoader.load(workspaceRoot) }
|
||||
if (instructions.isEmpty()) return
|
||||
eventStore.append(
|
||||
NewEvent(
|
||||
metadata = EventMetadata(
|
||||
eventId = EventId(java.util.UUID.randomUUID().toString()),
|
||||
sessionId = sessionId,
|
||||
timestamp = Clock.System.now(),
|
||||
schemaVersion = 1,
|
||||
causationId = null,
|
||||
correlationId = null,
|
||||
),
|
||||
payload = AgentInstructionsBoundEvent(
|
||||
sessionId = sessionId,
|
||||
workspaceRoot = workspaceRoot,
|
||||
sources = instructions.sources,
|
||||
content = instructions.content,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase-2 handoff for freestyle sessions, shared by every launcher that can finish a
|
||||
* planning graph (fresh run and all resume paths). Locks the plan and executes it,
|
||||
|
||||
Reference in New Issue
Block a user