Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion spec/SPECIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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/<name>/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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.*
113 changes: 113 additions & 0 deletions spec/schemas/agent-yaml.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@
},
"vendor_management": {
"$ref": "#/$defs/vendor_management_config"
},
"segregation_of_duties": {
"$ref": "#/$defs/segregation_of_duties_config"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -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
}
}
}
36 changes: 36 additions & 0 deletions src/adapters/claude-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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'));
}

Expand Down
37 changes: 37 additions & 0 deletions src/adapters/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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')}`);
}
Expand Down
Loading