Documentation
Places and rights

Set up the example places

Several pages show what Smeldr answers for a file in a repository: Connect an agent, Find the Decisions that apply and Show Claude Code the Decisions before it edits. This page sets up the places and Decisions their examples use, so your answers match theirs:

  • the Domain DOM2 "Payments", in the Organization;
  • the Area ARE1 "Billing", in DOM2, which covers internal/billing/** in the repository acme/app;
  • two ratified Decisions: D3 in DOM2 and D4 in ARE1.

It continues from Getting started, in the same directory, with the server running. Getting started left you with D2 in force in the Organization, so a file in ARE1 has three Decisions in force: D2, D3 and D4. The addresses are the ones that path gives. If you have made other records since, the ones below get later numbers than the page shows: each answer names the address it gave, so use that one. Domains and Areas explains what places are.

Where the two shells differ, a step shows the bash form first, then the PowerShell form. Commands shown once run unchanged in bash and in Windows PowerShell, with the files named as in Getting started. cmd.exe is not covered. The steps were run as written on Linux and in Windows PowerShell on Windows 11.

Load your token

In a new terminal, load your token and define mcp again, as in Getting started:

. ./.smeldr-cli.env

mcp() {
  curl -s http://localhost:8080/mcp/message \
    -H "Authorization: Bearer $SMELDR_TOKEN" \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/json, text/event-stream' \
    --data @"$1"
}

In PowerShell:

Get-Content .smeldr-cli.env | ForEach-Object { $k, $v = $_ -split '=', 2; Set-Item "env:$k" $v }

function mcp($file) {
  # The answer is saved and read back as UTF-8, so the console shows it as the server sent it.
  curl.exe -s http://localhost:8080/mcp/message `
    -H "Authorization: Bearer $env:SMELDR_TOKEN" `
    -H 'Content-Type: application/json' `
    -H 'Accept: application/json, text/event-stream' `
    --data "@$file" -o answer.json
  Get-Content answer.json -Encoding UTF8
}

Make the Domain

Create the Domain, then place it in the Organization:

cat > domain.json <<'EOF'
{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"create_domain","arguments":{
  "name":"Payments"}}}
EOF
mcp domain.json

cat > domain-place.json <<'EOF'
{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Domain","source_id":"DOM2",
  "relation_kind":"belongs_to_organization",
  "target_type":"Organization","target_id":"ORG1"}}}
EOF
mcp domain-place.json

In PowerShell:

@'
{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"create_domain","arguments":{
  "name":"Payments"}}}
'@ | Set-Content domain.json
mcp domain.json

@'
{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Domain","source_id":"DOM2",
  "relation_kind":"belongs_to_organization",
  "target_type":"Organization","target_id":"ORG1"}}}
'@ | Set-Content domain-place.json
mcp domain-place.json

The first answer holds the address DOM2. The server made DOM1 "General" on its first start.

Make the Area and the files it covers

Create the Area, place it in DOM2, and say which files it covers:

cat > area.json <<'EOF'
{"jsonrpc":"2.0","id":12,"method":"tools/call","params":{"name":"create_area","arguments":{
  "name":"Billing","approval_mode":"requires-approval"}}}
EOF
mcp area.json

cat > area-place.json <<'EOF'
{"jsonrpc":"2.0","id":13,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Area","source_id":"ARE1",
  "relation_kind":"belongs_to_domain",
  "target_type":"Domain","target_id":"DOM2"}}}
EOF
mcp area-place.json

cat > area-files.json <<'EOF'
{"jsonrpc":"2.0","id":14,"method":"tools/call","params":{"name":"create_coverage_rule","arguments":{
  "area":"ARE1","repository":"acme/app","pattern":"internal/billing/**"}}}
EOF
mcp area-files.json

In PowerShell:

@'
{"jsonrpc":"2.0","id":12,"method":"tools/call","params":{"name":"create_area","arguments":{
  "name":"Billing","approval_mode":"requires-approval"}}}
'@ | Set-Content area.json
mcp area.json

@'
{"jsonrpc":"2.0","id":13,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Area","source_id":"ARE1",
  "relation_kind":"belongs_to_domain",
  "target_type":"Domain","target_id":"DOM2"}}}
'@ | Set-Content area-place.json
mcp area-place.json

@'
{"jsonrpc":"2.0","id":14,"method":"tools/call","params":{"name":"create_coverage_rule","arguments":{
  "area":"ARE1","repository":"acme/app","pattern":"internal/billing/**"}}}
'@ | Set-Content area-files.json
mcp area-files.json

The first answer holds the address ARE1. requires-approval means a pull request that touches the Area's files waits for its approver. The pattern internal/billing/** covers every file under internal/billing in acme/app, at any depth.

Make the two Decisions

Propose each Decision and place it, the first in the Domain and the second in the Area:

cat > decision-domain.json <<'EOF'
{"jsonrpc":"2.0","id":15,"method":"tools/call","params":{"name":"create_decision","arguments":{
  "title":"Payments use idempotency keys",
  "scope":"engineering",
  "body":"Every payment request carries an idempotency key, so a retry never charges twice."}}}
EOF
mcp decision-domain.json

cat > decision-domain-place.json <<'EOF'
{"jsonrpc":"2.0","id":16,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Decision","source_id":"D3",
  "relation_kind":"belongs_to_domain",
  "target_type":"Domain","target_id":"DOM2"}}}
EOF
mcp decision-domain-place.json

cat > decision-area.json <<'EOF'
{"jsonrpc":"2.0","id":17,"method":"tools/call","params":{"name":"create_decision","arguments":{
  "title":"Invoices are immutable",
  "scope":"engineering",
  "body":"An issued invoice is never changed; a correction is a new invoice."}}}
EOF
mcp decision-area.json

cat > decision-area-place.json <<'EOF'
{"jsonrpc":"2.0","id":18,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Decision","source_id":"D4",
  "relation_kind":"belongs_to_area",
  "target_type":"Area","target_id":"ARE1"}}}
EOF
mcp decision-area-place.json

In PowerShell:

@'
{"jsonrpc":"2.0","id":15,"method":"tools/call","params":{"name":"create_decision","arguments":{
  "title":"Payments use idempotency keys",
  "scope":"engineering",
  "body":"Every payment request carries an idempotency key, so a retry never charges twice."}}}
'@ | Set-Content decision-domain.json
mcp decision-domain.json

@'
{"jsonrpc":"2.0","id":16,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Decision","source_id":"D3",
  "relation_kind":"belongs_to_domain",
  "target_type":"Domain","target_id":"DOM2"}}}
'@ | Set-Content decision-domain-place.json
mcp decision-domain-place.json

@'
{"jsonrpc":"2.0","id":17,"method":"tools/call","params":{"name":"create_decision","arguments":{
  "title":"Invoices are immutable",
  "scope":"engineering",
  "body":"An issued invoice is never changed; a correction is a new invoice."}}}
'@ | Set-Content decision-area.json
mcp decision-area.json

@'
{"jsonrpc":"2.0","id":18,"method":"tools/call","params":{"name":"assert_relation","arguments":{
  "source_type":"Decision","source_id":"D4",
  "relation_kind":"belongs_to_area",
  "target_type":"Area","target_id":"ARE1"}}}
'@ | Set-Content decision-area-place.json
mcp decision-area-place.json

The two answers to create_decision hold the addresses D3 and D4. Then ratify both, as the person who holds that right here:

./smeldr-cli transition Decision D3 --to ratified --rev 0
./smeldr-cli transition Decision D4 --to ratified --rev 0

Each answer says the Decision is ratified.

Check what applies to a file

./smeldr-cli decisions-for-paths --repo acme/app internal/billing/invoice.go
AREA  NAME     APPROVAL           PATHS
ARE1  Billing  requires-approval  1

DECISION  PLACE              TITLE
D2        organization ORG1  Store timestamps in UTC, with the offset kept
D3        domain DOM2        Payments use idempotency keys
D4        area ARE1          Invoices are immutable
3 Decisions in force; 0 paths uncovered

The file is in ARE1, so the Area's Decision applies to it, and so do the Domain's and the Organization's. Find the Decisions that apply explains the answer.