Shapes Specification

Version:
0.1.0
Status:
Working Draft
Date:
March 2026

Abstract

Shapes is an open specification born from the need to give engineers a layer above code — a way to define the intent, structure, and constraints of a system so that agents can fill it. But the model is not specific to software. A Shape can describe anything with intent and structure: a product, a research program, a novel, an organization. Humans define and approve Shapes; agents handle the work that fills them. Each Shape connects to the artifacts that realize it, the evidence that validates it, and the provenance that records where it came from.


1. Motivation

Revision history tells you what changed, but not what the work means. Change logs, task lists, and review trails are useful records, but they don't capture intent, invariants, or ownership boundaries.

As agents multiply and run tasks in parallel, the volume of changes outpaces what humans can meaningfully review. Shapes gives practitioners control over the evolution of their work without reviewing every change.

Agents interact with Shapes in three ways:

  • Build — propose changes that fill the Shape.
  • Review — evaluate whether proposed changes match the Shape.
  • Evolve — propose new Shapes or mutate existing ones as the project grows.

Shapes aims to:

  • Let practitioners define project structure at any granularity — from a single component to an entire system.
  • Enable agents to navigate from high-level concerns to concrete artifacts through explicit bindings.

Shapes does not replace version control, review workflows, or task tracking — it defines a semantic layer above them. It does not standardize storage or synchronization protocols or inline provenance records.


2. What is a Shape?

A Shape is a semantic unit that may represent a feature, component, workflow, boundary, or an entire project. Shapes compose into architectures that can span multiple projects and sources — internal and external. The best way to understand a Shape is to see one.

2.1 Example

Shapes originated from the need to give software engineers a semantic layer above code. The model itself is generic — use the toggle below to see how the same structure describes a software feature, a chapter in a novel, or a laboratory experiment. Each field is explained in the sections that follow — for now, read top to bottom to see how intent, constraints, realization, evidence, and provenance fit together in a single record.

child child constraint constraint amends Platform Auth Invitations Admin Guard Apple Sign-In
Shape
Constraint
Amendment
Canonical
Promoted
Proposed
Shape:
  id: 1
  name: Platform
  description: Top-level system encompassing authentication and team management.
  kind: system
  version: 1.0.0
  # → §3 Lifecycle
  status:
    canonical:
      date: "2025-12-01"
  # → §2.2 Intent
  intent:
    summary: >
      Provide a unified platform for user identity, access control,
      and team collaboration.
  children:
    - 2
    - 3
A software project with parent/child Shapes, a shared Constraint, and an Amendment

This example shows a standalone Shape. Shapes can also contain children and reference other Shapes, forming architectures that span project boundaries — see §7 Architecture.

2.2 Intent

Every first-class node in Shapes — Shapes, Amendments, and Constraints — carries an Intent. Intent captures the why behind a record: what it aims to achieve, what it deliberately excludes, and how success is measured. It is the semantic core that makes each record reviewable on its own terms, independent of the artifacts that realize it.

The uris list grounds the intent in external references — issue trackers, design documents, discussion threads. Beyond the core fields, Intent is an open map: projects add whatever fields suit their domain.

yaml
Intent:
  summary: string
  uris: [string]?
  # open map — add any fields your project needs
  <string>: any
Intent schema
yaml
intent:
  summary: Allow administrators to invite users by email.
  uris:
    - https://github.com/acme/invitations/issues/42
    - https://docs.example/design/invitations
  rationale: Reduce onboarding friction for new teams.
  goals:
    - Reduce setup friction for new teams
    - Keep invitation issuance restricted to trusted actors
  non_goals:
    - Guest access
  success_criteria:
    - Invitations accepted within 24h > 80%
  tradeoffs:
    - Simpler flow at the cost of no guest access
Common fields teams may adopt

2.3 The Shape Model

Inline children are Shapes owned by this parent. ShapeId children reference Shapes across boundaries. parents provides the inverse for bidirectional traversal. Because a Shape can appear as a child of multiple parents, the model supports DAG (directed acyclic graph) structures that can express any system topology.

The model should prefer explicitness at boundaries. A Shape should state what concern it represents, why it exists, what must remain true, and which concrete artifacts are expected to embody it.

yaml
Shape:
  id: ShapeId
  name: string
  description: string
  kind: string
  version: semver
  # Lineage → §3 Lifecycle
  predecessors: [ShapeId]?
  # → §3 Lifecycle
  # one of:
  status:
    proposed | promoted | canonical | rejected | abandoned | reverted:
      date: iso8601
      reason: string?
      uris: [string]?
    superseded:
      date: iso8601
      reason: string?
      uris: [string]?
      successors: [ShapeId]
  # → §2.2 Intent
  intent: Intent
  metadata:
    <string>: any
  constraints:
    - Constraint | ConstraintId
  # → §6.1 Realization Bindings
  realization:
    - RealizationBinding
  # → §6.2 Evidence
  evidence:
    - EvidenceRef
  # → §8 Boundaries and Extensibility
  provenance:
    - ProvenanceRef
  # → §4 Amendments
  amendment_log:
    - AmendmentRef
  # Composition
  parents: [ShapeId]?
  children:
    - Shape | ShapeId
Shape schema

ShapeId, AmendmentId, and ConstraintId are opaque identifiers. The specification prescribes no format, length, or generation strategy — implementations choose whatever suits their storage and coordination needs (UUIDs, integers, slugs, content hashes, etc.).

Versions follow semantic versioning (MAJOR.MINOR.PATCH). When an amendment canonicalizes, the Shape's version is bumped according to the amendment's semver_change field. The initial version for a newly proposed Shape is implementation-defined (e.g., 0.1.0 or 1.0.0).


3. Lifecycle

Every Shape, Amendment, and Constraint moves through a lifecycle. The first three states are progressive; the last three are terminal.

Progressive
ProposedA candidate under consideration.
PromotedIntent is established, realization may be incomplete.
CanonicalThe authoritative state, fully realized with sufficient evidence.

Terminal
RejectedNot part of the current project state.
SupersededNo longer current; a successor owns the concern.
AbandonedIncomplete and inactive.
RevertedPreviously progressive, now unwound.

Status is a tagged union — the lifecycle state is the key, so each variant structurally defines only the fields valid for that state. The superseded variant carries successors because replacement only makes sense for that transition; other variants cannot.

Lifecycle state changes are governed by preconditions and postconditions. For example, promotion may require that all declared constraints have a plan for enforcement, and canonicalization may require that realization bindings and evidence references are present and sufficient. The spec does not prescribe a fixed set of preconditions in this draft, but every state change should be reviewable and justified.

Structural operations — splitting a Shape into multiple children, merging sibling Shapes, or superseding one Shape with another — are expressed by transitioning the original Shape(s) to a terminal state and proposing new ones. The predecessors field on the new Shape(s) references the originals, while the status.successors field on the superseded Shape(s) references their replacements. The operation type is derived from cardinality: one predecessor to one successor is a supersede, one to many is a split, and many to one is a merge. This keeps the lifecycle model simple while still supporting large-scale reorganization with machine-readable lineage.

When a Shape is superseded, successors should be non-empty. The lineage graph must be acyclic, and all referenced IDs should resolve to existing records.

yaml
# Original Shape, now superseded
Shape:
  id: shape-auth-monolith
  name: Unified Auth Module
  version: 2.3.0
  status:
    superseded:
      date: "2026-03-10"
      reason: Split into separate authentication and authorization concerns
      successors: [shape-authn, shape-authz]

# New Shapes
Shape:
  id: shape-authn
  name: Authentication
  version: 0.1.0
  predecessors: [shape-auth-monolith]
  status:
    proposed:
      date: "2026-03-10"

Shape:
  id: shape-authz
  name: Authorization
  version: 0.1.0
  predecessors: [shape-auth-monolith]
  status:
    proposed:
      date: "2026-03-10"
Structural operation — split (1 → N)

4. Amendments

Changes to a Shape while it is still in Proposed status are direct edits to the proposal. Once a Shape reaches promoted or canonical status, further semantic changes are recorded as amendments rather than new Shapes. Each amendment is an immutable record. Corrections are recorded as subsequent amendments, never edits to prior ones.

Amendments follow the same lifecycle as Shapes: Proposed, Promoted, and Canonical. A proposed amendment declares what should change and why. A promoted amendment is accepted in direction — implementation begins, and the amendment accumulates its own realization bindings and evidence as the work progresses. A canonical amendment is fully realized and proven: the artifacts exist, the verification passes, the evidence is sufficient.

Amendments carry the same semantic fields as Shapes — intent, constraints, realization bindings, and evidence — because those are what an amendment must earn to reach canonical status. Think of each amendment as a self-contained record of change: what was proposed, what was built, what proves it works, and why it was accepted.

An amendment goes through independent review without touching the base Shape. When it reaches canonical status, its fields are integrated into the base Shape so that the base always reflects the current effective state. The base Shape acts as a materialized view of current truth; amendment records are the immutable audit trail.

yaml
Amendment:
  id: AmendmentId
  name: string
  description: string
  # → §2 What is a Shape?
  shape_id: ShapeId
  # monotonic sequence number within the shape
  seq: int
  # → §3 Lifecycle
  # one of:
  status:
    proposed | promoted | canonical | rejected | abandoned:
      date: iso8601
      reason: string?
      uris: [string]?
  semver_change: major | minor | patch
  # which parts of the Shape were touched
  # e.g. "intent.goals", "constraints"
  affected_paths:
    - string
  # → §2.2 Intent
  intent: Intent
  constraints:
    - Constraint | ConstraintId?
  # → §6.1 Realization Bindings
  realization:
    - RealizationBinding?
  # → §6.2 Evidence
  evidence:
    - EvidenceRef?
  initiated_by:
    type: human | agent | system
    identity: string?
    provenance_ref: string?
Amendment schema

When the amendment canonicalizes, its fields are merged into the base Shape and the Shape's version is bumped according to semver_change. The amendment record remains as the audit trail showing how each piece got there.

If an amendment is large enough to constitute a fundamental redesign, it may be more appropriate to supersede the Shape and propose a new one.

To see how amendments work in practice, here is the Team Invitations Shape from earlier — now showing the base Shape after an amendment has been applied, alongside the amendment record itself.

yaml
Shape:
  id: 3
  name: Invitations
  description: Email-based team invitation workflow.
  kind: feature
  version: 1.1.0
  # → §3 Lifecycle
  status:
    canonical:
      date: "2026-01-15"
  # → §2.2 Intent
  intent:
    summary: Allow administrators to invite users by email.
    goals:
      - Reduce setup friction for new teams
      - Keep invitation issuance restricted to trusted actors
      # applied from amendment 5
      - Support Apple sign-in for invitation acceptance
    non_goals:
      - Guest access
  constraints:
    - id: 1
      kind: invariant
      rule: only admins may create invitations
      enforcement: machine
    # applied from amendment 5
    - id: 2
      kind: requirement
      rule: invitation acceptance must support Apple sign-in
      enforcement: machine
    - 4
  # → §6.1 Realization Bindings
  realization:
    - uris:
        - https://github.com/acme/invitations/blob/a1b2c3d/src/service.rs#L40-L118
        # applied from amendment 5
        - https://github.com/acme/invitations/blob/a1b2c3d/src/apple_oauth.rs#L1-L95
      role: primary
  # → §6.2 Evidence
  evidence:
    - id: ci_123
      type: test_report
      uris:
        - https://ci.example/123
      trusted: true
    # applied from amendment 5
    - id: ci_456
      type: test_report
      uris:
        - https://ci.example/456
      trusted: true
  # → §8 Boundaries
  provenance:
    - type: agent_trace
      trace_record_id: 550e8400-e29b-41d4-a716-446655440000
  # → §4 Amendments
  amendment_log:
    - 5
Base Shape after amendment — always reflects current effective state
yaml
Amendment:
  id: 5
  name: Apple Sign-In
  description: Add Apple sign-in for invitation acceptance.
  # → §2 What is a Shape?
  shape_id: 3
  seq: 1
  # → §3 Lifecycle
  status:
    canonical:
      date: "2026-02-14"
  semver_change: minor
  affected_paths:
    - intent.goals
    - constraints
    - realization
    - evidence
  # → §2.2 Intent
  intent:
    summary: >
      Add Apple sign-in as an accepted authentication method
      for invitation acceptance, alongside existing Google support.
    rationale: >
      User research showed 34% of target users prefer Apple sign-in.
      Restricting to Google-only created unnecessary friction during
      team onboarding.
    goals:
      - Support Apple sign-in for invitation acceptance
  constraints:
    - id: 2
      kind: requirement
      rule: invitation acceptance must support Apple sign-in
      enforcement: machine
  # → §6.1 Realization Bindings
  realization:
    - uris:
        - https://github.com/acme/invitations/blob/a1b2c3d/src/apple_oauth.rs#L1-L95
      role: primary
  # → §6.2 Evidence
  evidence:
    - id: ci_456
      type: test_report
      uris:
        - https://ci.example/456
      trusted: true
  initiated_by:
    type: human
    identity: user.admin.jane
Amendment record for the Shape above

5. Constraints

Shapes and Amendments embed constraints inline when a rule is specific to a single record. But many constraints are cross-cutting — they apply to multiple Shapes across a system. Defining the same rule inline in every Shape that must obey it creates duplication and drift.

A standalone Constraint is a first-class graph node: it has its own identity, lifecycle, intent, realization bindings, and evidence. Shapes reference it by ID rather than repeating its content. In standalone form, a Constraint relates to Shapes the same way an Amendment does — through explicit references rather than nesting.

The dual model is deliberate. Inline constraints remain for Shape-specific rules that have no reason to be shared. Standalone Constraints are for rules that span boundaries — organization-wide policies, cross-service invariants, or compliance requirements that many Shapes must satisfy.

Constraints have their own lifecycle because enforcement is proven incrementally. A proposed Constraint declares the rule. A promoted Constraint is accepted in direction — teams begin implementing enforcement. A canonical Constraint is backed by realization bindings and evidence proving the rule holds.

5.1 Standalone Constraints

A standalone Constraint record carries the same semantic weight as a Shape: it declares what must be true, why, and how to prove it. The schema mirrors Shapes in structure — intent, realization, evidence, provenance — because a Constraint must earn its canonical status through the same process.

yaml
Constraint:
  id: ConstraintId
  name: string
  description: string
  kind: invariant | requirement | policy | limit
  rule: string
  enforcement: machine | human | hybrid
  version: semver
  # Lineage → §3 Lifecycle
  predecessors: [ConstraintId]?
  # → §3 Lifecycle
  # one of:
  status:
    proposed | promoted | canonical | rejected | abandoned | reverted:
      date: iso8601
      reason: string?
      uris: [string]?
    superseded:
      date: iso8601
      reason: string?
      uris: [string]?
      successors: [ConstraintId]
  intent: Intent
  # → §6.1 Realization Bindings
  realization:
    - RealizationBinding?
  # → §6.2 Evidence
  evidence:
    - EvidenceRef?
  # → §8 Boundaries and Extensibility
  provenance:
    - ProvenanceRef?
  # → §4 Amendments
  amendment_log:
    - AmendmentRef?
Constraint schema

The kind field classifies the nature of the rule. Invariant is a property that must always hold. Requirement is something the system must do. Policy is an organizational rule. Limit is a quantitative bound. This list is intentionally open — projects may add their own kinds.

The enforcement field indicates how the rule is upheld: machine for automated enforcement (validators, automated checks, rule engines), human for review-based enforcement, or hybrid when both are needed.

Standalone Constraints can be amended just like Shapes. If a rule evolves — "only admins" becomes "admins and org owners" — that change is recorded as an amendment to the Constraint, not as a new Constraint. The amendment log preserves the history of how the rule evolved.

yaml
Constraint:
  id: 4
  name: Admin Guard
  description: Only admin-role users may perform destructive actions.
  kind: policy
  rule: only users with the admin role may perform destructive actions
  enforcement: machine
  version: 1.0.0
  # → §3 Lifecycle
  status:
    canonical:
      date: "2025-11-20"
  intent:
    summary: >
      Restrict destructive operations (delete, revoke, disable) to
      admin-role users to prevent accidental or unauthorized data loss.
    rationale: >
      Incident INC-2024-031 traced to a member-role user accidentally
      deleting a production dataset. Policy adopted org-wide.
  # → §6.1 Realization Bindings
  realization:
    - uris:
        - https://github.com/acme/platform/blob/main/src/middleware/admin_guard.rs#L12-L45
      role: primary
  # → §6.2 Evidence
  evidence:
    - id: ci_789
      type: test_report
      uris:
        - https://ci.example/789
      trusted: true
A standalone Constraint describing an organization-wide policy

5.2 Constraint References

Inline constraints define rules specific to a single Shape. ConstraintId references point to standalone Constraints defined elsewhere — shared, cross-cutting rules that apply to many Shapes. The Constraint record carries all semantic weight; the reference is a simple pointer.

yaml
Shape:
  id: 3
  name: Invitations
  description: Email-based team invitation workflow.
  kind: feature
  version: 1.1.0
  status:
    canonical:
      date: "2026-01-15"
  intent:
    summary: Allow administrators to invite users by email.
  constraints:
    # inline: specific to this Shape
    - id: 1
      kind: invariant
      rule: only admins may create invitations
      enforcement: machine
    # shared: defined once, referenced by many Shapes
    # → §5.1 Standalone Constraints
    - 4
A Shape mixing inline constraints and constraint references

When an Amendment adds a constraint — whether inline or a reference — it is integrated into the base Shape upon canonicalization, the same merge process used for all other amendment fields.


6. Connecting to Artifacts

Shapes are semantic declarations. They become useful when connected to concrete artifacts — or to other Shapes — and backed by evidence. Because bindings and evidence can reference Shapes as well as artifacts, the model extends beyond a tree into a graph that can describe systems of systems.

6.1 Realization Bindings

Realization bindings connect a Shape to the artifacts that embody it: documents, designs, deliverables, references, verifications, or other project surfaces. A binding can also reference another Shape, so that one Shape is realized by the existence or canonical status of another — enabling composition across project boundaries. Each binding groups related URIs under a single role.

yaml
RealizationBinding:
  uris:
    - string
  role: primary | supporting | interface | verification | migration | docs
  revision: string?

6.2 Evidence

Evidence is distinct from realization. Realization answers, what artifacts embody this Shape? Evidence answers, why should the system believe the Shape is satisfied?

Evidence may include verification reports, automated check results, benchmarks, reviews, inspection records, or attestations. Evidence can also reference other Shapes — for example, a parent Shape may cite the canonical status of its child Shapes as proof of satisfaction. A Promoted Shape may accumulate evidence as work progresses toward canonicalization. The spec does not require a single trust model, but evidence references should be explicit enough for tools and reviewers to inspect them.


7. Boundaries and Extensibility

The Shapes specification records semantics and lifecycle management. Provenance systems record origin. That boundary is deliberate: a Shape may reference provenance, but it should not inline or redefine a separate provenance specification.

  • Shapes owns intent, constraints, semantic status, and the canonical project model.
  • Agent Trace or equivalent systems own contributor attribution, conversation lineage, and revision-scoped origin details.
  • Shapes may keep a lightweight provenance reference when semantic review needs a pointer back to origin records.

Shapes is intentionally open at the edges. Different projects will need different field vocabularies, constraint types, evidence sources, and realization roles. The draft therefore standardizes the semantic frame before it standardizes every possible payload.

Extensions should preserve the core separation of concerns. New Shape kinds, binding roles, or evidence types are acceptable so long as they do not blur the distinction between semantics, embodiment, proof, and provenance.