RACI Matrix Validator
business.raci_validate
Overview
You send the tasks, the roles and the letters assigned between them; we return whether the matrix satisfies the rules you enabled, and one entry per finding with the task or role it concerns. The two rules everybody agrees on — exactly one accountable per task, at least one responsible per task — are switches you control, so the verdict reflects your policy and not an opinion of ours. Findings we have no authority over come back as warnings instead: a role that holds nothing, a task nobody is assigned to, the same letter merged in twice. Responsible and accountable on the same role is normal practice and allowed by default; any other combination a role ends up holding on one task says two contradictory things and is reported once, naming the whole set, so the report does not depend on the order you listed the assignments in. Set a ceiling on consulted roles per task or accountable tasks per role and we will flag the overload as well. Nothing is stored, and role and task names are accepted but never echoed.
RACI matrices fail in a handful of predictable ways — two people accountable, nobody responsible, one person accountable for everything, a role left in from the last reorganisation — and they fail quietly, because a spreadsheet does not check itself. Making the rules explicit switches means the check can run in a form, in a pipeline, or in a review, and give the same answer each time.
Reliability
Fully deterministic: findings come back in a published order — assignment problems in the order you sent them, then task problems in task order, then role problems in role order — so two runs of the same matrix produce the same report byte for byte, and no map iteration decides anything. A letter conflict is a task problem reported once per role, in the order you declared the roles, and names the whole set that role holds on that task, so reordering the same assignments cannot change how many conflicts you are told about. Ids are compared exactly: padding is refused rather than trimmed, because trimming would merge two ids you meant to keep apart. The letter is the one enum here, and an enum is stripped of surrounding whitespace and upper-cased before it is matched — ' r ' is R — a tolerance that never extends to an id. Findings past maxIssues are left out of issues but still counted in issueCount and bySeverity, and truncated says so, so a capped report can never call a matrix valid because its errors were cut off. Failures: RACI_MATRIX_INVALID means the matrix cannot be read — no tasks or roles, an id that is empty, too long, padded or carrying a control character, a letter outside R, A, C, I, or an unaccepted property. RACI_ID_DUPLICATE means a task or role id is declared twice. RACI_LIMIT_EXCEEDED means more than 2000 tasks, 200 roles or 100000 assignments, so split the matrix. RACI_RULES_INVALID means a rule is not of its declared type or maxIssues is outside 1 to 10000. None is worth retrying unchanged.
Context footprint
The response is one entry per finding plus a small summary, and maxIssues is the ceiling you control. A clean 2000-task matrix answers in a few hundred bytes. A successful call costs 1 execution credit.
When to use it
Whenever a matrix is created or edited, and before anybody relies on it to know who decides.
When you need advice on who should own what, or when your matrix uses a letter vocabulary of its own.
Scope
Non-goals
- Does not judge whether the right people hold the right letters
- Does not invent an owner for a task that has none
- Does not store, publish or notify anything
- Does not rank tasks or roles by importance
- Does not echo the names you attach to tasks and roles
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| matrix | object | Yes | Closed RACI matrix of unique tasks, unique roles, and assignment objects that name a task, a role and a letter. |
| rules | object | No | Closed optional policy switches; omit the object to keep the published defaults. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| valid | boolean | Yes | Whether no ERROR-severity finding exists under the enabled rules. |
| issues | array | Yes | Bounded array of 0 through 10000 findings in the published task-then-role order. |
| summary | object | Yes | Closed RACI summary with counts, truncation, and the three headline tallies. |
| rules | object | Yes | Closed rules actually applied, with every default filled in. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"business.raci_validate","input":{"matrix":{"tasks":[{"id":"spec"}],"roles":[{"id":"pm"},{"id":"dev"}],"assignments":[{"taskId":"spec","roleId":"pm","letter":"A"},{"taskId":"spec","roleId":"dev","letter":"R"}]}}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("business.raci_validate", {"matrix":{"roles":[{"id":"pm"},{"id":"dev"},{"id":"qa"}],"tasks":[{"id":"spec"},{"id":"build"}],"assignments":[{"taskId":"spec","roleId":"pm","letter":"A"},{"taskId":"spec","roleId":"dev","letter":"R"},{"taskId":"spec","roleId":"qa","letter":"C"},{"taskId":"build","roleId":"pm","letter":"A"},{"taskId":"build","roleId":"dev","letter":"R"}]}});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| RACI_MATRIX_INVALID | 400 | No | The request payload failed this skill's input validation. |
| RACI_ID_DUPLICATE | 400 | No | The request payload failed this skill's input validation. |
| RACI_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| RACI_RULES_INVALID | 400 | No | The request payload failed this skill's input validation. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not judge whether the right people hold the right letters
- Does not invent an owner for a task that has none
- Does not store, publish or notify anything
- Does not rank tasks or roles by importance
- Does not echo the names you attach to tasks and roles
- Deciding who should be accountable — that is a management call
- Storing or publishing the matrix
- Matrices with letters beyond R, A, C and I: extend the vocabulary elsewhere first
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "business.raci_validate",
"input": {
"matrix": {
"roles": [
{
"id": "pm"
},
{
"id": "dev"
},
{
"id": "qa"
}
],
"tasks": [
{
"id": "spec"
},
{
"id": "build"
}
],
"assignments": [
{
"taskId": "spec",
"roleId": "pm",
"letter": "A"
},
{
"taskId": "spec",
"roleId": "dev",
"letter": "R"
},
{
"taskId": "spec",
"roleId": "qa",
"letter": "C"
},
{
"taskId": "build",
"roleId": "pm",
"letter": "A"
},
{
"taskId": "build",
"roleId": "dev",
"letter": "R"
}
]
}
}
}Examples
A clean matrix: one accountable and one responsible per task
{
"matrix": {
"roles": [
{
"id": "pm"
},
{
"id": "dev"
},
{
"id": "qa"
}
],
"tasks": [
{
"id": "spec"
},
{
"id": "build"
}
],
"assignments": [
{
"taskId": "spec",
"roleId": "pm",
"letter": "A"
},
{
"taskId": "spec",
"roleId": "dev",
"letter": "R"
},
{
"taskId": "spec",
"roleId": "qa",
"letter": "C"
},
{
"taskId": "build",
"roleId": "pm",
"letter": "A"
},
{
"taskId": "build",
"roleId": "dev",
"letter": "R"
}
]
}
}{
"valid": true,
"summary": {
"taskCount": 2,
"roleCount": 3,
"assignmentCount": 5,
"issueCount": 0,
"bySeverity": {},
"truncated": false,
"tasksWithoutAccountable": 0,
"tasksWithoutResponsible": 0,
"rolesWithoutAssignment": 0
},
"rules": {
"requireSingleAccountable": true,
"requireResponsible": true,
"allowCombined": true,
"maxIssues": 1000
},
"issues": []
}Two accountable roles on one task, and a task nobody owns — with R and A on one role accepted
{
"matrix": {
"roles": [
{
"id": "pm"
},
{
"id": "dev"
},
{
"id": "ops"
}
],
"tasks": [
{
"id": "spec"
},
{
"id": "deploy"
}
],
"assignments": [
{
"taskId": "spec",
"roleId": "pm",
"letter": "A"
},
{
"taskId": "spec",
"roleId": "dev",
"letter": "A"
},
{
"taskId": "spec",
"roleId": "dev",
"letter": "R"
},
{
"taskId": "deploy",
"roleId": "ops",
"letter": "C"
}
]
}
}{
"valid": false,
"summary": {
"taskCount": 2,
"roleCount": 3,
"assignmentCount": 4,
"issueCount": 3,
"bySeverity": {
"ERROR": 3
},
"truncated": false,
"tasksWithoutAccountable": 1,
"tasksWithoutResponsible": 1,
"rolesWithoutAssignment": 0
},
"rules": {
"requireSingleAccountable": true,
"requireResponsible": true,
"allowCombined": true,
"maxIssues": 1000
},
"issues": [
{
"code": "MULTIPLE_ACCOUNTABLE",
"severity": "ERROR",
"taskId": "spec",
"detail": "2 roles are accountable for this task. Accountability that is shared is accountability nobody holds: keep one A."
},
{
"code": "NO_ACCOUNTABLE",
"severity": "ERROR",
"taskId": "deploy",
"detail": "No role is accountable for this task. Assign exactly one A."
},
{
"code": "NO_RESPONSIBLE",
"severity": "ERROR",
"taskId": "deploy",
"detail": "No role is responsible for this task. Assign at least one R."
}
]
}Recommended use cases
- Gate a project-setup form until every task has exactly one owner
- Audit an inherited responsibility matrix before a handover
- Find the roles that own too much, before the person holding them tells you
- Keep one definition of a valid RACI across several teams' tooling
Avoid for
- Deciding who should be accountable — that is a management call
- Storing or publishing the matrix
- Matrices with letters beyond R, A, C and I: extend the vocabulary elsewhere first
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.