Skip to main content
Version: Current

Product · advanced — a legal service

The case. Open a company, then, optionally, subscribe to its accounting. Or subscribe to accounting alone, for a company that already exists.

What the example shows. An item that is a filled-in request, not a product: the guard (form → eligibility → quote) is the service. Two journeys share a skill. Accounting reads the result of the company opening in the same submit.

examples/actuelle/product-advanced.yaml
# Product · advanced — a legal service: open a company, then (optionally) its accounting.
# The item is a FILLED REQUEST, not a product: the select guard (form → eligibility → quote) is the
# product. Two journeys share one skill; the accounting reads the company the formation opened.
station:
id: statuts-express
name: Statuts Express

global:
language: fr
currency: EUR
locale: fr-FR

domain:
domain_type: legaltech
entity_name: service
entity_name_plural: services

agent:
tone: professional
name: Statuts Express
persona: "un assistant juridique précis qui accompagne les fondateurs"
rules:
- "Ne jamais donner de conseil juridique contraignant : présenter les options, laisser les outils valider et tarifer."
- "Citer le nom et le prix exacts renvoyés par les outils, en euros."
portals:
web:
widget:
origins: [https://statuts-express.example.fr]

apis:
- name: juridique
openapi_url: https://api.statuts-express.example.fr/openapi.json
base_url: https://api.statuts-express.example.fr
operations:
- {id: recommendLegalStructure, access: read}
- {id: checkFormationEligibility, access: read}
- {id: quoteFormation, access: read}
- {id: openFormationDossier, access: write, reversible: false}
- {id: getAccountingPlans, access: read}
- {id: checkAccountingEligibility, access: read}
- {id: quoteAccounting, access: read}
- {id: subscribeAccounting, access: write, reversible: cancelSubscription}
- {id: cancelSubscription, access: write}
auth: {type: api_key, key_name: Authorization, key_location: header, key_env: STATUTS_KEY}

skills:
- name: formation
auto_trigger: open-company
cognitive:
objective: "recommander la structure juridique adaptée au projet"
diagnose: [l'activité, le nombre d'associés, le capital]
invoke: {method: recommendLegalStructure}
kinds: {company_formation: {}}
present:
fields:
name: {from: label, type: text, role: title}
price: {from: base_fee, type: price, role: billed}
select:
max_items: 1 # one company is being formed
guards:
- form:
activity: {type: text, required: true, label: "Activité de la société"}
capital: {type: number, required: true, label: "Capital social (€)"}
associates: {type: integer, required: true, label: "Nombre d'associés"}
hq_address: {type: text, required: true, label: "Adresse du siège"}
- check: checkFormationEligibility # the tenant says whether this structure fits
- update: {price: quoteFormation} # …and what it costs for THIS request
submit:
- name: open
mode: request
tool: openFormationDossier
args:
body.structure: "$item.fields.code"
body.activity: "$item.fields.activity"
body.capital: "$item.fields.capital"
body.associates: "$item.fields.associates"
body.hq_address: "$item.fields.hq_address"
body.fee: "$item.price"
body.idempotency_key: "$action.key"
output: {company_id: "$output.company_id"}

render: {component: cards}
- name: accounting
cognitive:
objective: "recommander le plan de comptabilité adapté au chiffre d'affaires"
diagnose: [le chiffre d'affaires estimé, la structure choisie]
invoke: {method: getAccountingPlans}
kinds: {accounting_subscription: {}}
present:
fields:
name: {from: label, type: text, role: title}
price: {from: price, type: price, role: billed}
select:
max_items: 1
guards:
- form:
est_revenue: {type: number, required: true, label: "Chiffre d'affaires estimé (€)"}
siren: {type: text, required: false, label: "SIREN (société existante)"}
- check: checkAccountingEligibility
- update: {price: quoteAccounting}
submit:
- name: subscribe
mode: request
tool: subscribeAccounting
args:
body.plan: "$item.fields.code"
body.est_revenue: "$item.fields.est_revenue"
body.siren: "$item.fields.siren"
# Value at submit (ADR-028 §3): filed AFTER the formation, in the same submit, and held
# if the formation failed. Alone, it resolves empty and the SIREN is used.
body.company_id: "$submitted[formation.open].company_id"
body.fee: "$item.price"
body.fee_cadence: "$item.price_cadence"
render: {component: cards}

playbooks:
- name: open-company
goal: "ouvrir une société : la structure, puis (option) la comptabilité"
tasks:
formation: {skill: formation, required: true, label: "Votre société"}
accounting: {skill: accounting, required: false, label: "Votre comptabilité", after: [formation]}
- name: subscribe-accounting
goal: "souscrire la comptabilité d'une société existante (SIREN)"
tasks:
accounting: {skill: accounting, required: true, label: "Votre comptabilité"}

submit_guard:
form:
accept_terms: {type: boolean, required: true, label: "J'accepte les conditions générales"}
confirm: true

What happens​

stepCoreresult
"I'm creating an SAS with one partner"formation → recommendLegalStructure; auto_trigger opens open-companycards for the structures
an accounting plan asked for firststep_open: the accounting task has after: [formation]refused, with the reason: the company first
SAS chosenform (activity, capital, partners, head office), then checkFormationEligibility, then quoteFormationthe line enters with its own price
an accounting plan chosenform, eligibility, quotesecond line, monthly price
"Finalise"accept_terms + confirmopenFormationDossier, then subscribeAccounting with company_id
the opening failsADR-028 §3accounting is put on hold, never filed on a missing company
"I already have a SARL, SIREN 812…"the agent calls start_playbook: subscribe-accountingcompany_id empty, the SIREN is used

Key points​

  • $submitted[formation.open].company_id is a dependency at execution time: same submit, in order, and nothing is filed if the parent failed.
  • The price comes from the tenant, for this request: update: {price: quoteFormation}, passed on by body.fee.
  • openFormationDossier is declared reversible: false: the MCP door announces the submit as destructive. subscribeAccounting names the operation that undoes it (cancelSubscription); nothing calls it yet.
  • In open-company, after: [formation] enforces the order at the choice: accounting opens only once the company is chosen. The target version makes the opening a sub-playbook.