Semogram Docs
Workspace managementWrite controls

Write policies

Approve versioned mutation semantics separately from actor authorization

A write policy states how a supported destination may change records: append, replace, upsert, update or delete; identity keys; duplicate/conflict handling; omissions; schema changes; retention and commit boundaries. It is a versioned contract, not a grant to a person and not proof that every connector implements every option.

You need a Semogram account with applicable policy permissions. Owners/admins obtain the write-policy permissions through their role; Members need explicit grants. API callers need appropriate scopes, resource reach and an accountable current member for the governed policy path.

Lifecycle

StageEffect
ProposeSave a new immutable contract revision and reason
ReviewInspect semantics, scope, inherited constraints and destination support
Approve/rejectRecord a decision for the selected revision
BindSelect an approved revision for a supported pipeline node/endpoint
ExecuteRecheck policy state, actor permission and supported behavior
Suspend/retireMake the revision unavailable for future resolution/execution checks

Approval does not run a pipeline. Applying a policy to a pipeline changes its draft; review, validate and save the draft before execution. A suspended parent can also prevent an inherited child from resolving.

Example: keyed equipment output

Assume a dedicated equipment output target supports keyed upsert on equipment_id. Incoming records represent changes; omitted records should remain. Create a proposal named Equipment output updates with:

ControlValue
Incoming dataChanges since the last read (delta)
Allowed operationAdd or update by identity (upsert)
Identity columnsequipment_id
Duplicate inputReject
Conflicting valuesAllow overwrite
Missing recordsPreserve
Schema changesReject
Retention30 days; no physical deletion
Concurrent writesReject
Commit boundaryRow, only if supported by this destination
Invalid recordsReject

Confirm a real database primary key and the installed writer's semantics. Choose the actual supported commit boundary; a policy cannot create run-level atomicity on a row writer.

Open Settings → Write Policies → New policy. Choose workspace or project scope, fill the manual controls (or review an assistant proposal), add a reason and save. Open the exact revision, inspect its summary and approve with a reason if authorized. Use the apply page to choose an approved revision, project, pipeline and destination node. Validate/save the changed pipeline draft and test a bounded write.

Policy proposal prompt
Prepare an Equipment output updates policy for the supported equipment writer. Use delta input, keyed upsert on equipment_id, reject duplicates, permit overwriting matching values, preserve omitted records, reject schema changes and forbid physical deletion. Inspect actual destination atomicity before selecting a commit boundary. Show the proposed scope and settings for review before saving or approving.

The in-app policy author supports proposals. Read-only policy MCP tools inspect existing records; they do not propose/approve revisions.

Public routes exist: POST /api/v1/write-policies proposes a complete {name, projectId, policy, parent, reason} body; PATCH /api/v1/write-policies/<POLICY_UUID> records a decision with {version,status,reason,destructiveApproval}. GET collection/detail inspects records. POST /api/v1/write-policies/<POLICY_UUID>/bind takes planId, nodeId and version to alter a supported pipeline draft.

For the dedicated equipment example, this complete proposal body uses workspace scope. Choose a real supported target/atomicity before submitting. A proposal records semantics; it does not select a database connection.

Complete equipment policy proposal body
{
  "name": "Equipment output updates",
  "projectId": null,
  "parent": null,
  "reason": "Update equipment by its primary key; preserve other records and disallow deletion.",
  "policy": {
    "contractVersion": 1,
    "sourceState": "delta",
    "mutation": "upsert",
    "identity": { "keys": ["equipment_id"], "nullKeys": "reject" },
    "duplicates": "reject",
    "conflicts": "overwrite",
    "omission": "preserve",
    "emptySnapshot": "reject",
    "relationships": "preserve",
    "schemaEvolution": "reject",
    "partitionEvolution": "reject",
    "retention": { "minimumDays": 30, "physicalDelete": false },
    "compaction": "disabled",
    "concurrency": "reject",
    "atomicity": "row",
    "invalidRows": "reject"
  }
}

Read the returned id/version. To approve that exact version, PATCH its policy URL with { "version": <returned version>, "status": "approved", "reason": "Reviewed against the equipment writer and bounded fixture.", "destructiveApproval": true }. Upsert is classified as destructive because it can overwrite existing records; approval requires explicit destructive approval even though physical deletion is disabled. Only supply this approval and reason after reviewing those effects. Then bind its returned version to the actual pipeline/node and validate/save the changed draft.

Use policy:propose for proposals, policy:approve for approve/reject and policy:manage for suspend/retire. Binding also needs applicable pipeline-authoring access. The contract reference supplies complete policy fields; a fragment is not a full proposal request.

Use write_policy_list / write_policy_get to inspect policies, revision states and decision history. Workspace-only policies can be listed with workspaceOnly true. These tools require policy:read. For a supported endpoint, source_write_policy_bind is a distinct binding action with its own management checks.

Important boundaries

An authorized proposer with policy:approve can approve their own proposal; the current system does not enforce a different reviewer. Destructive combinations need explicit destructiveApproval. Mutation permissions such as data:write/data:delete/data:maintain are checked separately.

Workspace-wide policies can be used where supported across the workspace. Project policies remain in their project. Data endpoint source-write policy bindings require workspace-wide policies. A new revision does not silently update consumers pinned to the old revision.

Policy inheritance cannot weaken protected parent rules and rejects cycles/excessive depth. Inspect the entire applicable chain before approving. See Consumer access for workspace modes and Source write grants for caller-specific endpoint authorization.