Deal Management System (DMS)
The Structure-stage machinery. DealPlan as the typed action DAG two parties sign over; the deal lifecycle (Draft → Proposed → Accepted → Active → Completed); plan compilation to workflows; agreement projection as legal-style markdown; the deal_structurer agent persona; the dms-deals system workspace.
Where this sits in the alignment economy. The DMS is the machinery of the Structure stage. Once participants have reasoned, communicated, and negotiated a confirmed Intent, the DMS is what turns that Intent into a typed, hashable, signable DealPlan — and then drives the lifecycle that compiles the plan into an executable workflow, mirrors status back as the workflow runs, and renders the result as a readable agreement.
"Deal structuring" is the work the DMS does. Read the alignment-economy guide for the framing; read agents, knowledge & workspaces for the substrate the DMS runs on.
What the DMS is
The DMS (Deal Management System) is the domain layer that owns:
- Deal as a first-class domain object (not the same as a payment, a contract, or a swap — a deal is the legal-shaped wrapper around the on-chain artifacts it produces).
- DealPlan — a typed action DAG that describes what the deal does. Two parties sign over the plan's hash; subsequent rendering, execution, and audit all key off the same canonical object.
- The deal state machine — Draft → Proposed → Accepted → Active → Completed (with CounterOffered / Rejected / Cancelled / Defaulted / FailedAfterPartialExecution detours).
- Plan compilation — DealPlan → pipeline
WorkflowDefinition, submitted via HTTP to the agents pipeline runner. - Status mirroring — workflow events flow back as
deal_events, so the deal is the audit-trail unit. - Agreement projection — frames + DealPlan + agreement metadata render as a legal-style markdown agreement with recitals, clauses, governing law, and dispute resolution.
- Frame emission — every state transition writes frames into the deal's KG, so the deal is queryable knowledge alongside documents and conversations.
The current name reflects the scope: a loan is one specific deal kind among many — repos, distributions, structured products, service agreements, escrow arrangements — and the DMS handles the lifecycle uniformly across them.
The Deal lifecycle
The state machine, with the GraphQL mutation that drives each transition:
proposeDeal
│
▼
╭──────╮ ╭──────────╮
│ DRAFT│ ── propose ───► │ PROPOSED │
╰──────╯ ╰─────┬────╯
(wizard │
save state) ┌──────────┼─────────────┐
│ │ │
signDeal rejectDeal counterOfferDeal
│ │ │
▼ ▼ ▼
╭──────────╮ ╭──────────╮ ╭──────────────╮
│ ACCEPTED │ │ REJECTED │ │COUNTEROFFERED│
╰────┬─────╯ ╰──────────╯ ╰──────┬───────╯
│ │
│ (child deal in PROPOSED;
activateDeal parent in COUNTEROFFERED;
│ signing the child completes the cycle)
▼
╭──────────╮
│ ACTIVE │ one-shot pipeline runs;
╰────┬─────╯ periodic processing if applicable
│
┌────────┼──────────────┬────────────────┐
│ │ │ │
▼ ▼ ▼ ▼
╭──────────╮ ╭───────────╮ ╭────────────╮ ╭──────────────────┐
│COMPLETED │ │ CANCELLED │ │ DEFAULTED │ │FAILED_AFTER_ │
│ │ │ │ │ │ │PARTIAL_EXECUTION │
╰──────────╯ ╰───────────╯ ╰────────────╯ ╰──────────────────╯
all phases either party periodic one-shot failed
clean cancelled; processing mid-execution;
cleanup ran past grace compensation needs
period user OnFailure edges
Terminal states: Completed, Cancelled, Rejected,
Defaulted, FailedAfterPartialExecution. Active is the
in-progress state. Each transition writes a deal_events audit
record alongside the state change, so the deal state and audit trail
stay aligned.
Caller rules per mutation:
proposeDealsignDealDeal.parties (once each)rejectDealcounterOfferDealProposed deal; parent moves to CounterOffered)cancelDeal (from Proposed)proposer_entity_idcancelDeal (from Accepted)activateDealproposer_entity_idprocessDealPeriod (periodic phase)The DealPlan
A DealPlan is the immutable artefact that defines what the deal
does. It's a typed directed acyclic graph (the only allowed cycles
are explicit retry edges, bounded by a max_loop_iterations
validator). Each node is a typed action referencing a descriptor in
the DealActionRegistry by task_name.
The plan is the legal envelope. Two parties signing the deal
sign over plan_hash, not over any party's particular view of the
plan. Once locked at proposeDeal, the plan cannot be modified —
only superseded via counterOfferDeal, which creates a new child
deal with a new plan and a new hash.
Reference resolution inside the plan
Action inputs use placeholder references that get resolved at execution time:
$step.X.YY of an earlier step X in the plan DAG$cashflow.X$period.XThe validator type-checks references at proposal time — a deal that asks for a field that doesn't exist or has the wrong type is rejected before any party can sign.
Validation at proposal time
proposeDeal runs strict validation before locking the plan:
- All party entity_ids resolve and are distinct.
- The proposer is not also a party (no self-deals).
- The plan's action DAG is well-formed (no cycles except via retry edges, all step_ids unique, all references typed).
- All declared cashflows are wired into at least one step's input.
agreement_metadata.platform_terms_versionis set (the universal master terms must be pinned at proposal time so platform amendments can't retroactively alter signed agreements).
Drafts (saved via saveDealDraft) skip this validation so partial
authoring works. Strict validation only fires when the user clicks
Propose at the end of the wizard.
From Intent to executed Deal
The full Stage 3 (Negotiate) → Stage 4 (Structure) → Stage 5 (Execute) flow:
Stage 3 Stage 4 Stage 5
──────── ──────── ────────
Confirmed Intent
(with proposed terms, ──── deal_structurer agent composes DealPlan ──►
parties, cashflow refs) saveDealDraft (iterative)
validate Draft
▼ │
proposeDeal │
▼ ▼
PROPOSED ── signDeal ──► ACCEPTED ── activateDeal ──► pipeline submitted
│ to agents-api
optional: ▼
counterOfferDeal workflow runs
(loop) ▼
pipeline_status_mirror
writes deal_events
▼
ACTIVE / COMPLETED /
DEFAULTED / …
▼
on-chain artifacts settled
proposeDeal — locking the plan
mutation ProposeBondTrancheA {
dealFlow {
proposeDeal(input: {
name: "Tranche A — 2027 Q1 receivables",
parties: [{ entityId: "ENT-investor-12" }],
plan: { /* canonical-JSON DealPlan */ },
cashflowRef: "cashflow:tranche-A-2027-Q1",
idempotencyKey: "tranche-A-2027-Q1-propose-v1"
}) {
success
deal { id status planHash parties { entityId } }
}
}
}
Effect: a new row in deals with status Proposed, the proposer's
signature minted implicitly, plan locked, audit event emitted. The
counterparties receive an IntentProposed-style event (and a thread
notification in the workspace where the deal was raised — typically
the dms-deals system workspace or a regular WG).
signDeal — counterparty assent
mutation { dealFlow {
signDeal(input: { dealId: "DEAL-xxx" }) { success deal { status } }
}}
Each non-proposer party calls signDeal once. When the last
outstanding party signs, status flips Proposed → Accepted and
accepted_at is stamped. The plan_hash the party signs over is the
same canonical SHA-256 the proposer locked at proposeDeal — both
parties end up with cryptographically-identical evidence of what
they agreed to.
activateDeal — compile + submit
mutation { dealFlow {
activateDeal(input: { dealId: "DEAL-xxx" }) { success deal { status } }
}}
This is where structuring crosses into execution. activateDeal:
- Compiles the DealPlan's action DAG into a
WorkflowDefinition(the shape the agents pipeline runner consumes). - Submits the workflow to the agents pipeline runner.
- Marks the deal
Active. - The submitted workflow runs the one-shot phase first — typically the contract / swap / payment mutations against the federated GraphQL gateway that actualise the deal's terms on-chain.
- As workflow events fire, the platform mirrors them into
deal_eventsso the deal is the single audit-trail unit.
Periodic processing
Deals with a periodic_phase (loans with monthly coupons, repo
roll schedules, ABS waterfall distributions) keep running after the
one-shot phase. processDealPeriod(period_index) advances one
period at a time:
mutation { dealFlow {
processDealPeriod(input: { dealId: "DEAL-xxx", periodIndex: 3 }) {
success
}
}}
Idempotent on (deal_id, period_index) — a status check in
deal_periods short-circuits already-processed periods, so retries
are safe. Either party or a recognised backend scheduler can call this;
periodic-phase failures past the grace period transition the deal
to Defaulted with default-branch cleanup actions run.
Agreement projection — the deal as a readable agreement
A signed deal is more than a workflow spec — it's a legal-shaped agreement that humans need to read, audit, and reference. Deal events emit frames into the deal's KG, and the agreement projector loads those frames into a typed view plus rendered markdown.
The output is a structured markdown document with:
- Title (from
agreement_metadata.title_override, falling back to the matched Concept's display name). - Recitals — the "WHEREAS" preamble paragraphs the proposer authored, each numbered automatically.
- Definitions — defined terms extracted from frames and the manifest.
- Operative clauses — one per step in the DealPlan, rendered
from descriptor
ClauseTemplates with author overrides applied. - Master terms incorporation by reference — pinned at
platform_terms_version. - Boilerplate pack expansion — e.g.
"services_agreement_uk_2024","consumer_loan_uk_fca_2024". - Governing law + dispute resolution — from
agreement_metadataor, when absent, fallback to the matched Concept's manifest properties. - Signatories block with each party's signature timestamp.
GraphQL exposure: dealAgreement query returns the rendered
markdown; dealAgreementGraph returns the typed view for
programmatic consumers (MCP tools, structured display).
Plan-hash invariance
AgreementMetadata and ClauseMetadata are entirely optional —
plans authored before this module existed serialise byte-identically
because Option::None is filtered by the canonical-JSON hash
machinery. Adding agreement metadata to a new plan changes its
hash; populating it after signing is not possible. This is the
right safety property: the rendered agreement and the signed
plan_hash are always for the same canonical object.
The dms-deals working group
The agents binary auto-creates a system-owned working group with
category = "dms-deals", one per economy. This is where deal
workflows execute when the user-side workspace doesn't otherwise
have a home for them. The group id is installed at boot via
set_default_deal_workflow_group_id; pipeline_submission reads
it as a fallback when DMS_DEAL_WORKFLOW_GROUP_ID env var is unset.
Implications for application authors:
- Deal-related workflow threads (
pipeline_main,pipeline_task) fordms-deals-routed deals land in the system workspace, not the user's primary workspace. - If you want deal workflows to surface in a specific workspace's
chat stream, pass that workspace's id at
proposeDealtime via the appropriate input field (or set the env var per deployment). - The
dms-dealsworkspace is system-owned — members are auto-added based on the deal's parties; you don't manage it manually.
The deal_structurer seeded agent
The platform ships a seeded agent persona with agent_key = "deal_structurer" whose specific role is to compose DealPlans
from confirmed intents. It reads:
- The confirmed Intent (proposed terms, parties, asset identifiers).
- The relevant KG (asset frames, party history, prior deals).
- The applicable economy manifest (which Concepts are available, their defaults, their action descriptors).
…and produces a candidate DealPlan with:
- A typed action DAG sized to the deal's complexity.
- A draft
AgreementMetadatablock — recitals composed from the conversation history, governing-law selection from the parties' jurisdictions, boilerplate-pack matched against the deal Concept. - Wired-up cashflow references and period schedule (for multi-period deals).
The Structurer's output is itself a Pipeline Draft — it materialises
as an Intent the proposer reviews and confirms before
saveDealDraft + proposeDeal actually land. The Structurer
proposes; the human proposer commits. Same safety boundary as
every other agentic action.
Domain owners can fork and specialise the Structurer for their deal types (a lending Structurer biases toward loan templates; a treasury Structurer biases toward payment-approval templates).
Frame emission — the deal as queryable knowledge
Every state transition writes frames into the deal's KG:
proposeDealwrites frames for the proposer, each party, the cashflow config, the plan's structural roles.signDealupdates the relevant party'sAgreementStatefrom"proposed"to"signed"; clause renderers pick this up and flip the lifecycle markers in the rendered markdown.activateDealwrites the workflow id + initial period state.- Periodic-phase advancement writes per-period frames.
- Terminal transitions (Completed, Cancelled, Defaulted) write closing frames + summary statistics.
Once frames are in the deal's KG, every other tool — RAG queries, the agreement projector, conversation analyzers — can read the deal's state alongside any other knowledge in the workspace. The deal is not a black box. Its state, its history, its parties, and its cashflows are all first-class knowledge that downstream agents can reason over.
Common deal shapes
The DMS doesn't enforce specific instrument types — any DealPlan that compiles validates. But four shapes are common enough to ship as plan-template factories:
AgreementMetadata) and the lifecycle (propose → sign → activate).Custom DealPlans for novel deal kinds are first-class — domain
authors compose them in YAML/JSON and submit via
saveDealDraft + proposeDeal.
Connection to other systems
The DMS sits between Intent and chain:
╭───────────╮ ╭───────────╮ ╭────────╮ ╭───────────╮ ╭────────╮
│ Intent │ ──► │ DMS │ ──► │ Agents │ ──► │ Payments │ ──► │ Chain │
│ (Stage 3 │ │ (Stage 4) │ │pipeline│ │ (MQ) │ │ │
│ Negotiate)│ │ │ │ runner │ │ │ │ │
╰───────────╯ ╰─────┬─────╯ ╰───┬────╯ ╰───────────╯ ╰────────╯
│ │
│ ▼
│ workflow status events
│ │
└─◄──────────────┘
pipeline_status_mirror
writes deal_events
- Upstream (Intent): the confirmed Intent carries the
parameters the DMS needs to build a
DealPlan— proposer, parties, cashflow refs, agreement metadata. - Downstream (agents pipeline runner): the DMS compiles the
DealPlan to a
WorkflowDefinitionand submits via HTTP. The runner advances steps using all the normal workflow primitives (human_task, agent_task, signature_gate, automated). - Downstream (payments MQ): workflow steps that need on-chain
effect submit messages —
createSwap,createObligation,instantsend, etc. The MQ pipeline runs validation + execution; on-chain state ratchets. - Status feedback loop: the pipeline status mirror watches
workflow events and writes them as
deal_events, so the deal is the single audit-trail unit across the whole chain. Queryingdeal.eventsreturns the propose, sign, activate, every workflow step, every period transition, and the terminal state.
Querying deals
query MyDeals {
dealFlow {
dealsByProposer(status: PROPOSED) {
id
name
status
planHash
parties { entityId }
events { timestamp eventType payload }
}
dealsAsParty(status: ACCEPTED) {
id
name
status
agreementMarkdown # rendered agreement document
cashflowSummary { totalIn totalOut periods { … } }
}
}
}
Filter by status, by role (proposer vs party), or by deal kind
(via dealKind: "BUNDLE", etc.). The dealAgreement query
returns the rendered markdown; dealAgreementGraph returns the
typed view for programmatic consumers.
For periodic-phase deals, deal.periods returns each period's
status, scheduled date, and processing event log.
Pitfalls
Proposed deal as bindingAcceptedProposed deal is one-sided; only the proposer has signed. Wait for signDeal from every party. Status is the discriminator.counterOfferDeal (creates a child deal in Proposed status).Active without checking phasesActive covers both one-shot-running and periodic-running. Check the workflow status via deal.workflowStatus before acting on the deal's products.Defaulted after grace periodperiodic_phase, your application or backend scheduler must call processDealPeriod per period. The platform doesn't auto-advance.deal_structurer agent exists for this reason. Drive plan composition from a conversation, let the Structurer propose a candidate, let the human review + edit + propose. Pure-manual plan authoring is a power-user path.Reference
dealFlow.* namespace via the Apollo Router gatewaydealAgreement querydealAgreementGraph querySee also
- The alignment economy — the five-stage framing. The DMS implements the Structure stage.
- Agents, knowledge & workspaces —
the workspace machinery the DMS runs on top of, particularly
the
dms-dealssystem workspace and thedeal_structureragent persona. - Contracts & Obligations · Atomic Swaps · Collateralisation — the artifact shapes the DMS compiles its DealPlans down to.
- Cross-service walkthrough — an end-to-end deal flow with concrete HTTP / GraphQL calls.