Skip to main content

Agent Alignment Layer

Retrieval answers "what did we decide?" when somebody thinks to ask. The Agent Alignment Layer is the other half: it lets an AI coding assistant (Claude Code, Cursor, Copilot) check a proposed action against your decision graph before it takes it, whether or not anyone thought to ask.

This is the part no general-purpose retrieval can do. A contradiction is semantically opposite to the decision it violates, so the decision you are about to break is the one a similarity search is least likely to hand you unprompted.

How it works

  1. The agent proposes an action - open a PR, create a ticket, change a config.
  2. It calls check_proposed_action (or POST /alignment/check).
  3. Align retrieves candidate decisions by vector similarity.
  4. If a candidate is close enough, the Brain runs the full conflict taxonomy over it and explains the contradiction in the decision's own terms.
  5. The agent receives aligned / conflicting / no-context / unknown.

Retrieval thresholds

ThresholdValueWhat it does
Vector floor0.50Minimum similarity for a decision to be considered at all
High-similarity0.65Above this, the Brain is asked to confirm and explain
Organization floor0.30Org-wide standards are pulled at a lower floor on purpose - a team action that contradicts a company standard is usually worded oppositely and scores below the normal floor, but still has to be checked

unknown is not a pass - this is the important part

If the analysis service is unavailable, slow, or degraded, the check returns unknown, never a fall-through aligned.

{
"status": "unknown",
"reason": "brain_timeout",
"confidence": 0,
"relevant_decisions": [],
"message": "The alignment check could not be completed - the analysis service was unavailable. This is NOT a pass: treat it as unchecked and review the relevant decisions (or retry) before proceeding."
}

reason is one of brain_timeout, brain_error or brain_degraded.

The control fails closed. An earlier version of this endpoint aborted the analysis on a 5s timeout and reported the result as a fast-check aligned, which silently discarded correct conflicts - a check that cannot fail is not a check. If you are building on this API, treat unknown exactly as you would treat conflicting: surface it to the human. An agent that maps unknown onto "proceed" has re-introduced the bug.

Status meanings

StatusMeaningThe agent should...
alignedConsistent with, or unrelated to, existing decisionsProceed
conflictingContradicts one or more active decisionsStop. Surface the decisions and ask the human
no-contextNo relevant decisions foundProceed, and consider capturing this decision afterwards
unknownThe check could not runStop. Surface "could not check" - do not treat as a pass

A second, easily-missed case: the top-level status can be aligned while a decision in relevant_decisions has its own status of conflicted. That means a later decision overrode the one you matched, so aligned only tells you that you agree with a stale record. Check both.

MCP tool

The hosted server registers this tool as check_proposed_action. There is a diff-shaped sibling, check_alignment, which takes a git diff and prepends the changed file paths - both resolve to the same endpoint.

Input

{
"action_type": "jira_ticket",
"content": "Migrate user service to MongoDB for flexible schema",
"context": "Team: Backend, Project: AUTH"
}

Response (conflicting)

{
"status": "conflicting",
"confidence": 0.91,
"relevant_decisions": [
{
"id": "d-42",
"title": "Use PostgreSQL for all services",
"summary": "Team decided Postgres is our only data store",
"status": "active",
"similarity": 0.87,
"cite": "align-stack#1234",
"decision_url": "https://app.align.tech/decisions/d-42",
"url": "https://github.com/acme/api/pull/1234"
}
],
"conflicts": [
{
"decision_id": "d-42",
"title": "Use PostgreSQL for all services",
"reason": "Proposes MongoDB which contradicts the Postgres-only decision",
"severity": "critical",
"suggested_resolution": "Review decision d-42 before proceeding"
}
],
"check_event_id": "016d5567-e6fc-4c95-9210-a22bb107bbd0",
"message": "This action conflicts with 1 existing decision(s). Review the conflicts before proceeding."
}

decision_url opens the decision in Align; url is where it was originally decided. They are not interchangeable - do not present one as the other.

Close the loop: rate the conflict

Every check returns a check_event_id. Once you or the user have acted on a flag, record whether it was right:

{ "tool": "rate_conflict", "check_event_id": "016d5567-…", "verdict": "correct" }

Or over REST: POST /alignment/conflicts/{eventId}/feedback. A 409 with error: "feedback_conflict" means the rating could not be verifiably recorded: nothing was written, and retrying will not succeed - surface it to a human.

This is the only signal that tells the graph whether its flags are useful. A flag nobody judges teaches it nothing, and adjudicated precision is what GET /alignment/impact reports back.

REST API

curl -X POST https://api.align.tech/alignment/check \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"action_type": "pull_request",
"content": "Add MongoDB driver to user service",
"context": "Relates to JIRA-1234"
}'

The tenant comes from your API key. Do not send x-tenant-id on an authenticated request - it is ignored when an auth context is present, and it is only honoured for trusted service-to-service calls. See Trust & Security.

Action types

action_typeUse for
jira_ticketJira issue creation
pull_requestGitHub/GitLab PR description
slack_messageSlack or Teams messages
commit_messageGit commit messages
generalAnything else

Latency - budget for seconds, not milliseconds

The Brain runs an LLM over the full conflict taxonomy, and that is the point: an earlier 5s timeout aborted it on every real check.

Default analysis timeout20,000 ms (ALIGNMENT_ANALYZE_TIMEOUT_MS, digits only - "20s" is ignored and falls back to the default)
Shipped in the Helm chart60,000 ms - a ceiling, not a target
Measured in production, 2026-08-04p50 ~15s, p95 ~29s

Two consequences worth designing for. Do not put this on a keystroke path - it belongs at a decision point (pre-PR, pre-commit, pre-ticket), where seconds are acceptable. And set your own client timeout above the server's, or you will manufacture the unknown you were trying to avoid.

Agent integration example

const check = await mcp.callTool('check_proposed_action', {
action_type: 'jira_ticket',
content: `${ticket.title}\n\n${ticket.description}`,
context: `Project: ${ticket.project}`,
});

// unknown is handled FIRST and identically to conflicting - it is not a pass.
if (check.status === 'unknown') {
return `Align could not check this ticket (${check.reason}). Treat it as unchecked.`;
}

if (check.status === 'conflicting') {
return `This ticket conflicts with existing decisions:\n${
check.conflicts.map((c) => `- ${c.title}: ${c.reason}`).join('\n')
}\n\nProceed anyway?`;
}

In CI

The align CLI wraps the same endpoint for pull requests:

align check --ci --base origin/main --block-on-critical

Setup

Connect your assistant to the Align MCP server - see the AI Assistants (MCP) guide. For REST, authenticate with your API key.