From 217c92bab3e4e420c5fd6bd052d99f55fda1ad93 Mon Sep 17 00:00:00 2001 From: patel-lyzr Date: Fri, 27 Feb 2026 21:00:49 +0530 Subject: [PATCH 1/5] feat: add segregation of duties schema, types, and spec Add the `segregation_of_duties` subsection to the compliance schema with support for roles, conflict matrix, assignments, isolation levels, handoff workflows, and enforcement modes. - JSON Schema definition in agent-yaml.schema.json - TypeScript types in loader.ts ComplianceConfig interface - Spec documentation including DUTIES.md convention, validation rules, and regulatory reference table Closes #10 (part 1 of 4) --- spec/SPECIFICATION.md | 85 ++++++++++++++++++++- spec/schemas/agent-yaml.schema.json | 113 ++++++++++++++++++++++++++++ src/utils/loader.ts | 19 +++++ 3 files changed, 216 insertions(+), 1 deletion(-) diff --git a/spec/SPECIFICATION.md b/spec/SPECIFICATION.md index 44eeb59..a57ce3a 100644 --- a/spec/SPECIFICATION.md +++ b/spec/SPECIFICATION.md @@ -9,7 +9,7 @@ The standard is designed to be: - **Framework-agnostic** — works with Claude Code, OpenAI, LangChain, CrewAI, AutoGen, and others - **Git-native** — version control, branching, diffing, and collaboration built in -- **Compliance-ready** — first-class support for FINRA, Federal Reserve, and interagency regulatory requirements +- **Compliance-ready** — first-class support for FINRA, Federal Reserve, interagency regulatory requirements, and segregation of duties - **Composable** — agents can extend, depend on, and delegate to other agents ## 2. Directory Structure @@ -19,6 +19,7 @@ my-agent/ ├── agent.yaml # [REQUIRED] Agent manifest ├── SOUL.md # [REQUIRED] Identity and personality ├── RULES.md # Hard constraints and boundaries +├── DUTIES.md # Segregation of duties policy and role declaration ├── AGENTS.md # Framework-agnostic fallback instructions ├── README.md # Human documentation ├── skills/ # Reusable capability modules @@ -194,6 +195,48 @@ compliance: soc_report_required: false # SOC 2 report required vendor_ai_notification: true # Vendor must notify of AI changes subcontractor_assessment: false # Fourth-party risk assessed + + # Segregation of duties (multi-agent duty separation) + segregation_of_duties: + roles: # Define roles for agents (min 2) + - id: maker # Initiates/creates + description: Creates proposals and initiates actions + permissions: [create, submit] + - id: checker # Reviews/approves + description: Reviews and approves maker outputs + permissions: [review, approve, reject] + - id: executor # Executes approved work + description: Executes approved actions + permissions: [execute] + - id: auditor # Audits completed work + description: Reviews completed actions for compliance + permissions: [audit, report] + + conflicts: # SOD conflict matrix + - [maker, checker] # Maker cannot approve own work + - [maker, auditor] # Maker cannot audit own work + - [executor, checker] # Executor cannot approve what they execute + - [executor, auditor] # Executor cannot audit own execution + + assignments: # Bind roles to agents + loan-originator: [maker] + credit-reviewer: [checker] + loan-processor: [executor] + compliance-auditor: [auditor] + + isolation: + state: full # full | shared | none + credentials: separate # separate | shared + + handoffs: # Critical actions requiring multi-role handoff + - action: credit_decision + required_roles: [maker, checker] + approval_required: true + - action: loan_disbursement + required_roles: [maker, checker, executor] + approval_required: true + + enforcement: strict # strict | advisory ``` ### Example Minimal agent.yaml @@ -365,6 +408,30 @@ For regulated agents, RULES.md should include explicit regulatory constraints: - Never transmit restricted data across jurisdictional boundaries ``` +## 5a. DUTIES.md — Segregation of Duties + +Declares the agent's duties, role boundaries, and the system-wide SOD policy. DUTIES.md exists at two levels: + +**Root level** (`DUTIES.md`) — Documents the system-wide segregation of duties policy: all roles, the conflict matrix, handoff workflows, isolation policy, and enforcement mode. This is the SOD equivalent of `RULES.md` — it defines the policy that all agents in the system must follow. + +**Per-agent level** (`agents//DUTIES.md`) — Declares this specific agent's role, permissions, boundaries, and handoff participation. Each sub-agent's DUTIES.md answers: what is my role, what can I do, what must I not do, and who do I hand off to. + +### Root DUTIES.md Recommended Sections + +- **Roles** — Table of all roles, assigned agents, and permissions +- **Conflict Matrix** — Which role pairs cannot be held by the same agent +- **Handoff Workflows** — Step-by-step handoff chains for critical actions +- **Isolation Policy** — State and credential isolation levels +- **Enforcement** — Strict vs advisory mode + +### Per-Agent DUTIES.md Recommended Sections + +- **Role** — This agent's assigned role +- **Permissions** — What actions this agent can take +- **Boundaries** — Must/must-not rules specific to this role +- **Handoff Participation** — Where this agent sits in handoff chains +- **Isolation** — This agent's isolation constraints + ## 6. AGENTS.md — Framework-Agnostic Instructions Provides fallback instructions compatible with Cursor, Copilot, and other tools that read `AGENTS.md`. This file supplements `agent.yaml` + `SOUL.md` for systems that don't understand the gitagent format. @@ -864,6 +931,13 @@ A valid gitagent repository must: 5. All referenced tools must exist in `tools/` 6. All referenced sub-agents must exist in `agents/` 7. `hooks.yaml` scripts must exist at specified paths +8. If `compliance.segregation_of_duties` is present: + - `roles` must define at least 2 roles with unique IDs + - `conflicts` pairs must reference defined role IDs + - `assignments` must reference defined role IDs + - No agent in `assignments` may hold roles that appear together in `conflicts` + - `handoffs.required_roles` must reference defined role IDs and include at least 2 + - Assigned agents should exist in the `agents` section ## 19. CLI Commands @@ -942,6 +1016,15 @@ All schemas are in `spec/schemas/`: | SR 21-8 | BSA/AML Model Risk | `compliance.model_risk` for AML agents | | CFPB Circular 2022-03 | Adverse Action + AI | `compliance.data_governance.lda_search` | +### Segregation of Duties References + +| Document | Subject | gitagent Impact | +|----------|---------|-----------------| +| FINOS AI Governance Framework | Multi-Agent Isolation & Segmentation | `compliance.segregation_of_duties` | +| SOC 2 Type II | Logical Access Controls | `segregation_of_duties.isolation` | +| SR 11-7 Section IV | Independent Review | `segregation_of_duties.conflicts` (maker/checker separation) | +| FINRA 3110 | Supervisory Systems (duty separation) | `segregation_of_duties.handoffs` | + --- *This specification is a living document. Contributions welcome.* diff --git a/spec/schemas/agent-yaml.schema.json b/spec/schemas/agent-yaml.schema.json index 6bf666c..acb7d91 100644 --- a/spec/schemas/agent-yaml.schema.json +++ b/spec/schemas/agent-yaml.schema.json @@ -429,6 +429,9 @@ }, "vendor_management": { "$ref": "#/$defs/vendor_management_config" + }, + "segregation_of_duties": { + "$ref": "#/$defs/segregation_of_duties_config" } }, "additionalProperties": false, @@ -662,6 +665,116 @@ } }, "additionalProperties": false + }, + + "segregation_of_duties_config": { + "type": "object", + "description": "Segregation of duties configuration for multi-agent systems. Ensures no single agent has complete control over critical processes.", + "properties": { + "roles": { + "type": "array", + "description": "Roles that agents can hold in this system", + "items": { + "type": "object", + "required": ["id", "description"], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "Role identifier (snake_case)" + }, + "description": { + "type": "string", + "description": "Human-readable role description" + }, + "permissions": { + "type": "array", + "items": { + "type": "string", + "enum": ["create", "submit", "review", "approve", "reject", "execute", "audit", "report"] + }, + "uniqueItems": true, + "description": "Permissions granted to this role" + } + }, + "additionalProperties": false + }, + "minItems": 2 + }, + "conflicts": { + "type": "array", + "description": "Pairs of role IDs that cannot be held by the same agent (SOD matrix)", + "items": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 2, + "maxItems": 2 + } + }, + "assignments": { + "type": "object", + "description": "Maps agent names to their assigned roles", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "isolation": { + "type": "object", + "description": "Isolation level between agents with different roles", + "properties": { + "state": { + "type": "string", + "enum": ["full", "shared", "none"], + "description": "'full': agents cannot access each other's state. 'shared': read-only cross-access. 'none': no isolation." + }, + "credentials": { + "type": "string", + "enum": ["separate", "shared"], + "description": "'separate': each role has its own credential scope. 'shared': agents share credentials." + } + }, + "additionalProperties": false + }, + "handoffs": { + "type": "array", + "description": "Critical actions requiring multi-role participation", + "items": { + "type": "object", + "required": ["action", "required_roles"], + "properties": { + "action": { + "type": "string", + "description": "Action type requiring handoff (e.g., credit_decision, loan_disbursement)" + }, + "required_roles": { + "type": "array", + "items": { "type": "string" }, + "minItems": 2, + "description": "Roles that must participate sequentially" + }, + "approval_required": { + "type": "boolean", + "description": "Whether explicit approval is needed at each handoff", + "default": true + } + }, + "additionalProperties": false + } + }, + "enforcement": { + "type": "string", + "enum": ["strict", "advisory"], + "description": "'strict': SOD violations are errors. 'advisory': SOD violations are warnings.", + "default": "strict" + } + }, + "additionalProperties": false } } } diff --git a/src/utils/loader.ts b/src/utils/loader.ts index 991ebcf..38f5084 100644 --- a/src/utils/loader.ts +++ b/src/utils/loader.ts @@ -115,6 +115,25 @@ export interface ComplianceConfig { vendor_ai_notification?: boolean; subcontractor_assessment?: boolean; }; + segregation_of_duties?: { + roles?: Array<{ + id: string; + description: string; + permissions?: string[]; + }>; + conflicts?: Array<[string, string]>; + assignments?: Record; + isolation?: { + state?: string; + credentials?: string; + }; + handoffs?: Array<{ + action: string; + required_roles: string[]; + approval_required?: boolean; + }>; + enforcement?: string; + }; } export function loadAgentManifest(dir: string): AgentManifest { From 30a5fd7afdf39df9bcd6f347cb90931361859b47 Mon Sep 17 00:00:00 2001 From: patel-lyzr Date: Fri, 27 Feb 2026 21:01:22 +0530 Subject: [PATCH 2/5] feat: add SOD validation, audit reporting, and init scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validate.ts: 16 validation rules for SOD (role uniqueness, conflict detection, assignment integrity, handoff validation, risk tier checks) - audit.ts: new "Segregation of Duties" section in audit report - init.ts: DUTIES.md scaffolding in full template Part 2 of 4 — depends on feat/sod-1-spec-schema --- src/commands/audit.ts | 61 +++++++++++++++++- src/commands/init.ts | 32 ++++++++++ src/commands/validate.ts | 134 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 2 deletions(-) diff --git a/src/commands/audit.ts b/src/commands/audit.ts index cfeda64..1d4a5ed 100644 --- a/src/commands/audit.ts +++ b/src/commands/audit.ts @@ -162,8 +162,65 @@ export const auditCommand = new Command('audit') info(' No vendor dependencies — vendor management not required'); } + // Segregation of Duties + heading('8. Segregation of Duties'); + if (c.segregation_of_duties) { + const sod = c.segregation_of_duties; + auditCheck('Roles defined (≥2)', !!(sod.roles && sod.roles.length >= 2)); + auditCheck('Conflict matrix defined', !!(sod.conflicts && sod.conflicts.length > 0)); + auditCheck('Role assignments configured', !!(sod.assignments && Object.keys(sod.assignments).length > 0)); + auditCheck('State isolation configured', !!sod.isolation?.state); + auditCheck('State isolation is full', sod.isolation?.state === 'full'); + auditCheck('Credential segregation configured', !!sod.isolation?.credentials); + auditCheck('Credentials are separate', sod.isolation?.credentials === 'separate'); + auditCheck('Handoff workflows defined', !!(sod.handoffs && sod.handoffs.length > 0)); + auditCheck('Enforcement is strict', sod.enforcement === 'strict'); + + if (sod.assignments) { + info(' Role assignments:'); + for (const [agent, roles] of Object.entries(sod.assignments)) { + label(' ' + agent, roles.join(', ')); + } + } + + if (sod.conflicts) { + info(' Conflict rules:'); + for (const [a, b] of sod.conflicts) { + info(` ${a} <-> ${b}`); + } + } + + // Check for SOD violations in assignments + if (sod.assignments && sod.conflicts) { + let violationFound = false; + for (const [agentName, assignedRoles] of Object.entries(sod.assignments)) { + for (const [roleA, roleB] of sod.conflicts) { + if (assignedRoles.includes(roleA) && assignedRoles.includes(roleB)) { + error(` VIOLATION: Agent "${agentName}" holds conflicting roles "${roleA}" and "${roleB}"`); + violationFound = true; + } + } + } + if (!violationFound) { + success(' No SOD violations detected in role assignments'); + } + } + + if (sod.handoffs) { + info(' Handoff requirements:'); + for (const h of sod.handoffs) { + label(' ' + h.action, `${h.required_roles.join(' → ')} (approval: ${h.approval_required !== false ? 'yes' : 'no'})`); + } + } + } else if (manifest.agents && Object.keys(manifest.agents).length >= 2) { + warn(' Segregation of duties not configured for multi-agent system'); + warn(' Consider adding segregation_of_duties for duty separation controls'); + } else { + info(' Single-agent system — segregation of duties not applicable'); + } + // Compliance artifacts - heading('8. Compliance Artifacts'); + heading('9. Compliance Artifacts'); auditCheck('compliance/ directory exists', existsSync(join(dir, 'compliance'))); auditCheck('regulatory-map.yaml exists', existsSync(join(dir, 'compliance', 'regulatory-map.yaml'))); auditCheck('validation-schedule.yaml exists', existsSync(join(dir, 'compliance', 'validation-schedule.yaml'))); @@ -171,7 +228,7 @@ export const auditCommand = new Command('audit') auditCheck('RULES.md exists', existsSync(join(dir, 'RULES.md'))); // Hooks for audit trail - heading('9. Audit Hooks'); + heading('10. Audit Hooks'); const hooksExist = existsSync(join(dir, 'hooks', 'hooks.yaml')); auditCheck('hooks/hooks.yaml exists', hooksExist); if (hooksExist) { diff --git a/src/commands/init.ts b/src/commands/init.ts index 3eff35f..38c9f55 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -262,6 +262,36 @@ metadata: Describe the skill instructions here. `; +const FULL_DUTIES_MD = `# Duties + +System-wide segregation of duties policy. + +## Roles + +| Role | Agent | Permissions | Description | +|------|-------|-------------|-------------| +| (define roles) | (assign agents) | (list permissions) | (describe duty) | + +## Conflict Matrix + +No single agent may hold both roles in any pair: + +- (define role conflicts) + +## Handoff Workflows + +(Define critical actions that require multi-role handoff) + +## Isolation Policy + +- **State isolation:** (full | shared | none) +- **Credential segregation:** (separate | shared) + +## Enforcement + +(strict | advisory) +`; + const REGULATORY_MAP = `mappings: [] `; @@ -346,6 +376,7 @@ export const initCommand = new Command('init') createFile(join(dir, 'SOUL.md'), STANDARD_SOUL_MD); createFile(join(dir, 'RULES.md'), FULL_RULES_MD); createFile(join(dir, 'AGENTS.md'), AGENTS_MD); + createFile(join(dir, 'DUTIES.md'), FULL_DUTIES_MD); createDir(join(dir, 'skills', 'example-skill')); createFile(join(dir, 'skills', 'example-skill', 'SKILL.md'), SKILL_MD); @@ -392,6 +423,7 @@ export const initCommand = new Command('init') success('Created SOUL.md'); success('Created RULES.md'); success('Created AGENTS.md'); + success('Created DUTIES.md'); success('Created skills/example-skill/SKILL.md'); success('Created knowledge/index.yaml'); success('Created memory/MEMORY.md + memory.yaml'); diff --git a/src/commands/validate.ts b/src/commands/validate.ts index a5fa696..b568a21 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -236,6 +236,140 @@ function validateCompliance(dir: string): ValidationResult { } } + // Segregation of Duties validation + const sod = c.segregation_of_duties; + if (sod) { + const roleIds = sod.roles?.map(r => r.id) ?? []; + + // Must define at least 2 roles + if (!sod.roles || sod.roles.length < 2) { + result.valid = false; + result.errors.push('[SOD] segregation_of_duties.roles must define at least 2 roles'); + } + + // Role IDs must be unique + if (roleIds.length !== new Set(roleIds).size) { + result.valid = false; + result.errors.push('[SOD] segregation_of_duties.roles contains duplicate role IDs'); + } + + // Conflict pairs must reference defined roles + if (sod.conflicts) { + for (const pair of sod.conflicts) { + for (const roleId of pair) { + if (!roleIds.includes(roleId)) { + result.valid = false; + result.errors.push( + `[SOD] Conflict references undefined role "${roleId}". Defined roles: ${roleIds.join(', ')}` + ); + } + } + if (pair[0] === pair[1]) { + result.valid = false; + result.errors.push(`[SOD] Role "${pair[0]}" cannot conflict with itself`); + } + } + } + + // Assignments must reference defined roles and check for conflicts + if (sod.assignments) { + for (const [agentName, assignedRoles] of Object.entries(sod.assignments)) { + for (const roleId of assignedRoles) { + if (!roleIds.includes(roleId)) { + result.valid = false; + result.errors.push(`[SOD] Agent "${agentName}" assigned undefined role "${roleId}"`); + } + } + + // Core SOD check: no agent holds conflicting roles + if (sod.conflicts) { + for (const [roleA, roleB] of sod.conflicts) { + if (assignedRoles.includes(roleA) && assignedRoles.includes(roleB)) { + const msg = `[SOD] Agent "${agentName}" holds conflicting roles: "${roleA}" and "${roleB}"`; + if (sod.enforcement === 'advisory') { + result.warnings.push(msg); + } else { + result.valid = false; + result.errors.push(msg); + } + } + } + } + + // Assigned agents should exist in manifest.agents + if (manifest.agents && !manifest.agents[agentName]) { + result.warnings.push(`[SOD] Agent "${agentName}" in assignments not found in agents section`); + } + } + } + + // Handoff required_roles must reference defined roles + if (sod.handoffs) { + for (const handoff of sod.handoffs) { + for (const roleId of handoff.required_roles) { + if (!roleIds.includes(roleId)) { + result.valid = false; + result.errors.push( + `[SOD] Handoff for "${handoff.action}" references undefined role "${roleId}"` + ); + } + } + const uniqueRoles = new Set(handoff.required_roles); + if (uniqueRoles.size < 2) { + result.valid = false; + result.errors.push( + `[SOD] Handoff for "${handoff.action}" must require at least 2 distinct roles` + ); + } + } + } + + // High/critical risk tier recommendations + if (c.risk_tier === 'high' || c.risk_tier === 'critical') { + if (sod.enforcement === 'advisory') { + result.warnings.push( + `[SOD] Risk tier "${c.risk_tier}" recommends enforcement: "strict", got "advisory"` + ); + } + if (!sod.isolation || sod.isolation.state !== 'full') { + result.warnings.push( + `[SOD] Risk tier "${c.risk_tier}" recommends isolation.state: "full" for full state segregation` + ); + } + if (!sod.isolation || sod.isolation.credentials !== 'separate') { + result.warnings.push( + `[SOD] Risk tier "${c.risk_tier}" recommends isolation.credentials: "separate"` + ); + } + } + + // SOD without conflicts is meaningless + if (!sod.conflicts || sod.conflicts.length === 0) { + result.warnings.push( + '[SOD] No conflicts defined — segregation_of_duties without conflict rules has no enforcement value' + ); + } + + // Every role should be assigned to at least one agent + if (sod.assignments && sod.roles) { + const assignedRoleIds = new Set(Object.values(sod.assignments).flat()); + for (const role of sod.roles) { + if (!assignedRoleIds.has(role.id)) { + result.warnings.push(`[SOD] Role "${role.id}" is defined but not assigned to any agent`); + } + } + } + } + + // Recommend SOD for multi-agent high/critical risk setups + if (!sod && manifest.agents && Object.keys(manifest.agents).length >= 2) { + if (c.risk_tier === 'high' || c.risk_tier === 'critical') { + result.warnings.push( + '[SOD] Multi-agent system with high/critical risk tier — consider configuring segregation_of_duties' + ); + } + } + return result; } From a76c6ea7006a36fc642f00c33373c792add20491 Mon Sep 17 00:00:00 2001 From: patel-lyzr Date: Fri, 27 Feb 2026 21:01:38 +0530 Subject: [PATCH 3/5] feat: add SOD constraints to system-prompt and claude-code adapters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/adapters/claude-code.ts | 36 ++++++++++++++++++++++++++++++++++ src/adapters/system-prompt.ts | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/adapters/claude-code.ts b/src/adapters/claude-code.ts index 104cf59..b9c074a 100644 --- a/src/adapters/claude-code.ts +++ b/src/adapters/claude-code.ts @@ -26,6 +26,12 @@ export function exportToClaudeCode(dir: string): string { parts.push(rules); } + // DUTIES.md → segregation of duties policy + const duty = loadFileIfExists(join(agentDir, 'DUTIES.md')); + if (duty) { + parts.push(duty); + } + // Skills — loaded via skill-loader const skillsDir = join(agentDir, 'skills'); const skills = loadAllSkills(skillsDir); @@ -77,6 +83,36 @@ export function exportToClaudeCode(dir: string): string { complianceParts.push('- All actions are audit-logged'); } + if (c.segregation_of_duties) { + const sod = c.segregation_of_duties; + complianceParts.push('\n### Segregation of Duties'); + complianceParts.push(`Enforcement: ${sod.enforcement ?? 'strict'}`); + if (sod.assignments) { + complianceParts.push('\nRole assignments:'); + for (const [agent, roles] of Object.entries(sod.assignments)) { + complianceParts.push(`- ${agent}: ${roles.join(', ')}`); + } + } + if (sod.conflicts) { + complianceParts.push('\nConflict rules (must not be same agent):'); + for (const [a, b] of sod.conflicts) { + complianceParts.push(`- ${a} <-> ${b}`); + } + } + if (sod.handoffs) { + complianceParts.push('\nRequired handoffs:'); + for (const h of sod.handoffs) { + complianceParts.push(`- ${h.action}: ${h.required_roles.join(' → ')}`); + } + } + if (sod.isolation?.state === 'full') { + complianceParts.push('- Agent state is fully isolated per role'); + } + if (sod.isolation?.credentials === 'separate') { + complianceParts.push('- Credentials are segregated per role'); + } + } + parts.push(complianceParts.join('\n')); } diff --git a/src/adapters/system-prompt.ts b/src/adapters/system-prompt.ts index 782bc12..95f5ede 100644 --- a/src/adapters/system-prompt.ts +++ b/src/adapters/system-prompt.ts @@ -25,6 +25,12 @@ export function exportToSystemPrompt(dir: string): string { parts.push(rules); } + // DUTIES.md + const duty = loadFileIfExists(join(agentDir, 'DUTIES.md')); + if (duty) { + parts.push(duty); + } + // Skills — loaded via skill-loader const skillsDir = join(agentDir, 'skills'); const skills = loadAllSkills(skillsDir); @@ -82,6 +88,37 @@ export function exportToSystemPrompt(dir: string): string { constraints.push('- Do not process any personally identifiable information'); } + if (c.segregation_of_duties) { + const sod = c.segregation_of_duties; + constraints.push('- Segregation of duties is enforced:'); + if (sod.assignments) { + for (const [agentName, roles] of Object.entries(sod.assignments)) { + constraints.push(` - Agent "${agentName}" has role(s): ${roles.join(', ')}`); + } + } + if (sod.conflicts) { + constraints.push('- Duty separation rules (no single agent may hold both):'); + for (const [a, b] of sod.conflicts) { + constraints.push(` - ${a} and ${b}`); + } + } + if (sod.handoffs) { + constraints.push('- The following actions require multi-agent handoff:'); + for (const h of sod.handoffs) { + constraints.push(` - ${h.action}: must pass through roles ${h.required_roles.join(' → ')}${h.approval_required !== false ? ' (approval required)' : ''}`); + } + } + if (sod.isolation?.state === 'full') { + constraints.push('- Agent state/memory is fully isolated per role — do not access another agent\'s state'); + } + if (sod.isolation?.credentials === 'separate') { + constraints.push('- Credentials are segregated per role — use only credentials assigned to your role'); + } + if (sod.enforcement === 'strict') { + constraints.push('- SOD enforcement is STRICT — violations will block execution'); + } + } + if (constraints.length > 0) { parts.push(`## Compliance Constraints\n${constraints.join('\n')}`); } From 877c6efb869ba727cd2e601b11f40639591d70dc Mon Sep 17 00:00:00 2001 From: patel-lyzr Date: Fri, 27 Feb 2026 21:01:50 +0530 Subject: [PATCH 4/5] feat: add SOD examples, DUTIES.md files, and README documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - examples/full/agent.yaml: segregation_of_duties config with analyst, reviewer, and auditor roles - examples/full/DUTIES.md: root-level SOD policy (roles, conflicts, handoffs, isolation, enforcement) - examples/full/agents/fact-checker/DUTIES.md: per-agent role declaration - examples/full/compliance/regulatory-map.yaml: duty_segregation mapping - README.md: SOD pattern section, updated directory tree, compliance docs Part 4 of 4 — depends on feat/sod-3-adapters --- README.md | 55 ++++++++++++++++++-- examples/full/DUTIES.md | 40 ++++++++++++++ examples/full/agent.yaml | 36 +++++++++++++ examples/full/agents/fact-checker/DUTIES.md | 36 +++++++++++++ examples/full/compliance/regulatory-map.yaml | 23 ++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 examples/full/DUTIES.md create mode 100644 examples/full/agents/fact-checker/DUTIES.md diff --git a/README.md b/README.md index 0377bd1..ca22070 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Every AI framework has its own structure. There's no universal, portable way to - **Git-native** — Version control, branching, diffing, and collaboration built in - **Framework-agnostic** — Export to any framework with adapters -- **Compliance-ready** — First-class support for FINRA, Federal Reserve, and SEC regulatory requirements +- **Compliance-ready** — First-class support for FINRA, Federal Reserve, SEC, and segregation of duties - **Composable** — Agents can extend, depend on, and delegate to other agents ## The Standard @@ -34,6 +34,7 @@ my-agent/ │ │ # ── Behavior & Rules ────────────────────────────────── ├── RULES.md # Hard constraints, must-always/must-never, safety boundaries +├── DUTIES.md # Segregation of duties policy and role boundaries ├── AGENTS.md # Framework-agnostic fallback instructions │ │ # ── Capabilities ────────────────────────────────────── @@ -58,7 +59,8 @@ my-agent/ ├── agents/ # Sub-agent definitions (recursive structure) │ └── fact-checker/ │ ├── agent.yaml -│ └── SOUL.md +│ ├── SOUL.md +│ └── DUTIES.md # This agent's role, permissions, boundaries ├── examples/ # Calibration interactions (few-shot) │ │ # ── Runtime ─────────────────────────────────────────── @@ -76,6 +78,31 @@ When an agent learns a new skill or writes to memory, it opens a branch + PR for Human-in-the-Loop +### Segregation of Duties (SOD) +No single agent should control a critical process end-to-end. Define roles (`maker`, `checker`, `executor`, `auditor`), a conflict matrix (which roles can't be the same agent), and handoff workflows — all in `agent.yaml` + `DUTIES.md`. The validator catches violations before deployment. + +```yaml +compliance: + segregation_of_duties: + roles: + - id: maker + description: Creates proposals + permissions: [create, submit] + - id: checker + description: Reviews and approves + permissions: [review, approve, reject] + conflicts: + - [maker, checker] # maker cannot approve own work + assignments: + loan-originator: [maker] + credit-reviewer: [checker] + handoffs: + - action: credit_decision + required_roles: [maker, checker] + approval_required: true + enforcement: strict +``` + ### Live Agent Memory The `memory/` folder holds a `runtime/` subfolder where agents write live knowledge — `dailylog.md`, `key-decisions.md`, and `context.md` — persisting state across sessions. @@ -183,6 +210,18 @@ compliance: model_risk: validation_cadence: quarterly ongoing_monitoring: true + segregation_of_duties: + roles: + - id: analyst + permissions: [create, submit] + - id: reviewer + permissions: [review, approve, reject] + conflicts: + - [analyst, reviewer] + assignments: + compliance-analyst: [analyst] + fact-checker: [reviewer] + enforcement: strict ``` ## CLI Commands @@ -218,6 +257,16 @@ gitagent has first-class support for financial regulatory compliance: - **Reg S-P** — Customer privacy, PII handling - **CFPB Circular 2022-03** — Explainable adverse action, Less Discriminatory Alternative search +### Segregation of Duties +- **Roles & Permissions** — Define maker, checker, executor, auditor roles with controlled permissions +- **Conflict Matrix** — Declare which role pairs cannot be held by the same agent +- **Handoff Workflows** — Require multi-agent participation for critical actions (credit decisions, regulatory filings) +- **Isolation** — Full state and credential segregation between roles +- **DUTIES.md** — Root-level policy + per-agent role declarations +- **Enforcement** — Strict (blocks deployment) or advisory (warnings only) + +Inspired by [Salient AI](https://www.trysalient.com/)'s purpose-built agent architecture and the [FINOS AI Governance Framework](https://air-governance-framework.finos.org/mitigations/mi-22_multi-agent-isolation-and-segmentation.html). + Run `gitagent audit` for a full compliance checklist against your agent configuration. ## Adapters @@ -264,7 +313,7 @@ See the `examples/` directory: - **`examples/minimal/`** — 2-file hello world (agent.yaml + SOUL.md) - **`examples/standard/`** — Code review agent with skills, tools, and rules -- **`examples/full/`** — Production compliance agent with all directories, hooks, workflows, sub-agents, and regulatory artifacts +- **`examples/full/`** — Production compliance agent with all directories, hooks, workflows, sub-agents, SOD with DUTIES.md, and regulatory artifacts - **`examples/gitagent-helper/`** — Helper agent that assists with creating gitagent definitions - **`examples/lyzr-agent/`** — Example Lyzr Studio integration diff --git a/examples/full/DUTIES.md b/examples/full/DUTIES.md new file mode 100644 index 0000000..b3ba390 --- /dev/null +++ b/examples/full/DUTIES.md @@ -0,0 +1,40 @@ +# Duties + +System-wide segregation of duties policy for the compliance-analyst agent system. + +## Roles + +| Role | Agent | Permissions | Description | +|------|-------|-------------|-------------| +| Analyst | compliance-analyst | create, submit | Performs regulatory analysis, generates findings and reports | +| Reviewer | fact-checker | review, approve, reject | Reviews analysis for accuracy, verifies claims against authoritative sources | +| Auditor | (unassigned) | audit, report | Audits completed reviews and maintains the compliance trail | + +## Conflict Matrix + +No single agent may hold both roles in any pair: + +- **Analyst <-> Reviewer** — The agent that produces findings cannot approve them +- **Analyst <-> Auditor** — The agent that produces findings cannot audit them +- **Reviewer <-> Auditor** — The agent that approves findings cannot audit the approval + +## Handoff Workflows + +### Regulatory Filing +1. **Analyst** creates the filing draft and submits for review +2. **Reviewer** verifies accuracy against authoritative sources, approves or rejects +3. Approval required at each step before proceeding + +### Customer Communication +1. **Analyst** drafts the communication +2. **Reviewer** checks for FINRA 2210 compliance (fair, balanced, no misleading statements) +3. Approval required before any communication is sent + +## Isolation Policy + +- **State isolation: full** — Each agent operates with its own memory and state. No agent may read or modify another agent's working memory. +- **Credential segregation: separate** — Each role has its own credential scope. The analyst's data access credentials are distinct from the reviewer's. + +## Enforcement + +Enforcement mode is **strict**. Any SOD violation (e.g., assigning conflicting roles to the same agent) will fail validation and block deployment. diff --git a/examples/full/agent.yaml b/examples/full/agent.yaml index 986edff..5257175 100644 --- a/examples/full/agent.yaml +++ b/examples/full/agent.yaml @@ -96,6 +96,42 @@ compliance: soc_report_required: true vendor_ai_notification: true subcontractor_assessment: true + segregation_of_duties: + roles: + - id: analyst + description: Performs regulatory analysis and generates findings + permissions: + - create + - submit + - id: reviewer + description: Reviews analysis for accuracy and completeness + permissions: + - review + - approve + - reject + - id: auditor + description: Audits completed reviews and maintains compliance trail + permissions: + - audit + - report + conflicts: + - [analyst, reviewer] + - [analyst, auditor] + - [reviewer, auditor] + assignments: + compliance-analyst: [analyst] + fact-checker: [reviewer] + isolation: + state: full + credentials: separate + handoffs: + - action: regulatory_filing + required_roles: [analyst, reviewer] + approval_required: true + - action: customer_communication + required_roles: [analyst, reviewer] + approval_required: true + enforcement: strict tags: - compliance - financial-services diff --git a/examples/full/agents/fact-checker/DUTIES.md b/examples/full/agents/fact-checker/DUTIES.md new file mode 100644 index 0000000..5367a44 --- /dev/null +++ b/examples/full/agents/fact-checker/DUTIES.md @@ -0,0 +1,36 @@ +# Duties + +## Role + +**Reviewer** — Reviews analysis for accuracy and completeness. + +## Permissions + +- **review** — Examine outputs produced by the analyst +- **approve** — Approve findings that meet accuracy and compliance standards +- **reject** — Reject findings that are inaccurate, incomplete, or non-compliant + +## Boundaries + +### Must +- Verify all factual claims against authoritative regulatory sources before approving +- Reject any finding that cannot be independently verified +- Document the basis for every approval or rejection decision + +### Must Not +- Create original analysis or findings (analyst role only) +- Modify the analyst's work — only approve or reject +- Access the analyst's working state or memory +- Use credentials assigned to other roles +- Audit own review decisions (auditor role only) + +## Handoff Participation + +| Action | Position in Chain | Receives From | Hands Off To | +|--------|------------------|---------------|--------------| +| regulatory_filing | Step 2 | analyst | (terminal — approved or rejected) | +| customer_communication | Step 2 | analyst | (terminal — approved or rejected) | + +## Isolation + +This agent operates under **full state isolation** with **separate credentials**. It cannot access the compliance-analyst's memory, state, or data access tokens. diff --git a/examples/full/compliance/regulatory-map.yaml b/examples/full/compliance/regulatory-map.yaml index 091c534..83ff16d 100644 --- a/examples/full/compliance/regulatory-map.yaml +++ b/examples/full/compliance/regulatory-map.yaml @@ -77,3 +77,26 @@ mappings: controls: - vendor_supervisory_procedures - vendor_ai_change_notification + + - capability: duty_segregation + rules: + - id: finos-ai-governance + name: "FINOS AI Governance — Multi-Agent Isolation" + controls: + - role_definition + - conflict_matrix_enforcement + - assignment_validation + - state_isolation + - credential_segregation + - id: finra-3110-sod + name: "FINRA Rule 3110 — Supervisory Separation" + controls: + - maker_checker_separation + - approval_workflow_enforcement + - independent_review_requirement + - id: soc2-logical-access + name: "SOC 2 — Logical Access Controls" + controls: + - role_based_access_control + - credential_isolation + - cross_boundary_approval From 7a74547f5a05173c7fc05cfd3531c7afe10c1ce1 Mon Sep 17 00:00:00 2001 From: patel-lyzr Date: Sat, 28 Feb 2026 01:15:56 +0530 Subject: [PATCH 5/5] fix: align DUTIES.md entries in README directory tree Match the comment alignment style used by RULES.md and AGENTS.md in the grouped category format. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca22070..72236d0 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ my-agent/ │ │ # ── Behavior & Rules ────────────────────────────────── ├── RULES.md # Hard constraints, must-always/must-never, safety boundaries -├── DUTIES.md # Segregation of duties policy and role boundaries +├── DUTIES.md # Segregation of duties policy and role boundaries ├── AGENTS.md # Framework-agnostic fallback instructions │ │ # ── Capabilities ────────────────────────────────────── @@ -60,7 +60,7 @@ my-agent/ │ └── fact-checker/ │ ├── agent.yaml │ ├── SOUL.md -│ └── DUTIES.md # This agent's role, permissions, boundaries +│ └── DUTIES.md # This agent's role, permissions, boundaries ├── examples/ # Calibration interactions (few-shot) │ │ # ── Runtime ───────────────────────────────────────────