Skip to content

Commit ec8dbcd

Browse files
patel-lyzrclaude
andcommitted
feat: add SOD constraints to system-prompt and claude-code adapters
- system-prompt.ts: exports SOD role assignments, conflict rules, handoff requirements, isolation constraints, and DUTIES.md content - claude-code.ts: includes SOD subsection in Compliance output and loads DUTIES.md into generated CLAUDE.md Part 3 of 4 — depends on feat/sod-2-cli-commands Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0c94bb6 commit ec8dbcd

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

src/adapters/claude-code.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ export function exportToClaudeCode(dir: string): string {
2626
parts.push(rules);
2727
}
2828

29+
// DUTIES.md → segregation of duties policy
30+
const duty = loadFileIfExists(join(agentDir, 'DUTIES.md'));
31+
if (duty) {
32+
parts.push(duty);
33+
}
34+
2935
// Skills — loaded via skill-loader
3036
const skillsDir = join(agentDir, 'skills');
3137
const skills = loadAllSkills(skillsDir);
@@ -77,6 +83,36 @@ export function exportToClaudeCode(dir: string): string {
7783
complianceParts.push('- All actions are audit-logged');
7884
}
7985

86+
if (c.segregation_of_duties) {
87+
const sod = c.segregation_of_duties;
88+
complianceParts.push('\n### Segregation of Duties');
89+
complianceParts.push(`Enforcement: ${sod.enforcement ?? 'strict'}`);
90+
if (sod.assignments) {
91+
complianceParts.push('\nRole assignments:');
92+
for (const [agent, roles] of Object.entries(sod.assignments)) {
93+
complianceParts.push(`- ${agent}: ${roles.join(', ')}`);
94+
}
95+
}
96+
if (sod.conflicts) {
97+
complianceParts.push('\nConflict rules (must not be same agent):');
98+
for (const [a, b] of sod.conflicts) {
99+
complianceParts.push(`- ${a} <-> ${b}`);
100+
}
101+
}
102+
if (sod.handoffs) {
103+
complianceParts.push('\nRequired handoffs:');
104+
for (const h of sod.handoffs) {
105+
complianceParts.push(`- ${h.action}: ${h.required_roles.join(' → ')}`);
106+
}
107+
}
108+
if (sod.isolation?.state === 'full') {
109+
complianceParts.push('- Agent state is fully isolated per role');
110+
}
111+
if (sod.isolation?.credentials === 'separate') {
112+
complianceParts.push('- Credentials are segregated per role');
113+
}
114+
}
115+
80116
parts.push(complianceParts.join('\n'));
81117
}
82118

src/adapters/system-prompt.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export function exportToSystemPrompt(dir: string): string {
2525
parts.push(rules);
2626
}
2727

28+
// DUTIES.md
29+
const duty = loadFileIfExists(join(agentDir, 'DUTIES.md'));
30+
if (duty) {
31+
parts.push(duty);
32+
}
33+
2834
// Skills — loaded via skill-loader
2935
const skillsDir = join(agentDir, 'skills');
3036
const skills = loadAllSkills(skillsDir);
@@ -82,6 +88,37 @@ export function exportToSystemPrompt(dir: string): string {
8288
constraints.push('- Do not process any personally identifiable information');
8389
}
8490

91+
if (c.segregation_of_duties) {
92+
const sod = c.segregation_of_duties;
93+
constraints.push('- Segregation of duties is enforced:');
94+
if (sod.assignments) {
95+
for (const [agentName, roles] of Object.entries(sod.assignments)) {
96+
constraints.push(` - Agent "${agentName}" has role(s): ${roles.join(', ')}`);
97+
}
98+
}
99+
if (sod.conflicts) {
100+
constraints.push('- Duty separation rules (no single agent may hold both):');
101+
for (const [a, b] of sod.conflicts) {
102+
constraints.push(` - ${a} and ${b}`);
103+
}
104+
}
105+
if (sod.handoffs) {
106+
constraints.push('- The following actions require multi-agent handoff:');
107+
for (const h of sod.handoffs) {
108+
constraints.push(` - ${h.action}: must pass through roles ${h.required_roles.join(' → ')}${h.approval_required !== false ? ' (approval required)' : ''}`);
109+
}
110+
}
111+
if (sod.isolation?.state === 'full') {
112+
constraints.push('- Agent state/memory is fully isolated per role — do not access another agent\'s state');
113+
}
114+
if (sod.isolation?.credentials === 'separate') {
115+
constraints.push('- Credentials are segregated per role — use only credentials assigned to your role');
116+
}
117+
if (sod.enforcement === 'strict') {
118+
constraints.push('- SOD enforcement is STRICT — violations will block execution');
119+
}
120+
}
121+
85122
if (constraints.length > 0) {
86123
parts.push(`## Compliance Constraints\n${constraints.join('\n')}`);
87124
}

0 commit comments

Comments
 (0)