Guide · shapes
Use when
A person wants a type, a property or a relationship added, changed or removed in a Shape that the project already has.
Looking for something else?
A new Shape for a new domain (recipe create-a-shape), or a public Shape you adopt as it is (card Shape). Designing what the Shape should hold, which this recipe does not cover.
Outcome
The Shape has a new published version with a message. Each entity that exists follows the change and takes the new properties. Otherwise the person knows that it stays on the old version, and why.Before you start
- Know your credential:
penumbra whoami. It prints the kind of credential, but not your role or a key’s scopes. If you do not know the role, ask the person. An owner or an admin publishes. A project API key needs the scopeshapes.draft.publish. Its publish waits for approval only if the project’s policy holdsshape_change(card rule shape-draft.7). - Read the Shape and its versions:
penumbra shapes show <shape>andpenumbra shapes log <shape> --limit 3. Note the newest version and its message. If no Shape of the project fits the domain, do not bend one. Create a new Shape (recipe create-a-shape). - Ask what the person wants in their words. Write down each type, property or relationship that changes, and the value the new property should hold.
- Count what exists:
penumbra graph counts.
Steps
-
Open an edit draft of the current version:
penumbra shapes edit <shape>.penumbra shapes fork <shape>makes a separate Shape instead (card rule shape-draft.1). MCP: inexecute,const shape = await penumbra.shapes.open({ name })starts or continues the draft of that Shape.- Expect:
Draft <id> is open at revision 1. Keep the draft id.
- Expect:
-
Pull the definition:
penumbra shapes pull <draft-id>. MCP:shape.read({ part: "model" }).- Expect:
Wrote <name>.shape.json.
- Expect:
-
Edit the file. Prefer changes that older entities follow: add an optional
property or a type, widen an enum, or make a required property optional (card
rule shape.4). To rename, change
nameand keep the ref (card rule shape.2), and expect older entities to stay behind (card rule shape.5). Keep the old property when you can, and add the new one beside it. A new optional property goes into thepropertieslist of its type: -
Push the file:
penumbra shapes push <name>.shape.json. MCP:shape.define({ types, relationships })orshape.modify([{ op, ... }]).- Expect:
Synced draft <id> to <name>.shape.json: revision <n>. Onrevision_conflict, pull again and reapply your edits (card rule shape-draft.2).
- Expect:
-
Check the draft:
penumbra shapes check <draft-id>. MCP:shape.validate().- Expect:
Draft <id> is valid at revision <n>and exit code 0. Fix each diagnostic, push and check again (card rule shape-draft.4).
- Expect:
-
Read the diff:
penumbra shapes diff <draft-id>. MCP:shape.read({ part: "changes" })lists the changes but no impact or bump, so use the CLI diff to judge them.- Expect: a list of changes, each with its impact, and a recommended bump.
An added property shows
(creating)andminor. A rename shows(preserving)andpatch. - If every change is
(preserving)or(creating)and nothing is renamed, older entities follow it. Go to step 7. - If any change is
(losing)or(breaking), or the bump ismajor, or something is renamed, stop. Follow problem breaking-shape-change. Tell the person, and publish only after they choose.
- Expect: a list of changes, each with its impact, and a recommended bump.
An added property shows
-
Publish:
penumbra shapes publish <draft-id> -m "<what changes>". MCP:shape.submit({ note }). A held submit returns a pending value; follow it withcheck_status.- Expect, for a person’s own session:
Published version <n> of Shape <id>.and exit code 0. - If the policy holds
shape_change, a key or a connected agent gets exit code 4 andpending. Give the person the approval URL and follow it withpenumbra operations wait <handle>(problem change-waits-for-approval). Nothing is published until it is approved. - When
waitends withoutcome: succeeded, read the new version number frompenumbra shapes log <shape>. The JSON thatwaitprints holds a different number.
- Expect, for a person’s own session:
-
Give the entities their new values. This works across a change that older
entities follow. For each entity that needs the new property, read it with
penumbra context entity <entity-id> --jsonand noteentity.revision. The text output does not print the revision. Then runpenumbra graph update <entity-id> --revision <n> --properties '<every property, with the new one>'. The update replaces the whole property map (card rule entity.2). Usepenumbra graph update, not a workspace: a workspace plans the change under the version of the entity, and refuses the new property (card rule shape.6). MCP:update_nodein the full catalog.- Expect:
updated node <id>andcommit: <n>. Read the entity again: its revision is one higher, and itsartifact_digestis the newest.
- Expect:
- To extract with the new version, start a new extraction (recipe extract-files). It opens its own workspace and reads the newest version (card rule extraction.15). A workspace that already holds work in this Shape keeps its old version (card rule shape.6). Penumbra does not extract Files again, and it does not recheck entities, after a publish. To find entities that no longer match their Files, use recipe find-stale-entities.
Check
penumbra shapes log <shape>shows the new version first, with your message.- Run
penumbra context explore --shape-id <shape-id> --limit 200 --json. For each entity that you updated in step 8, theartifact_digestunder shape equals the newestartifact_digestinpenumbra shapes log <shape> --json. The explore output lists no properties, so runpenumbra context entity <entity-id> --jsonand find the new value inproperties. - For every other entity that stays on an older digest, you can say why. An additive change leaves it on the old version until an edit saves it under the new one, and it still reads. A breaking change leaves it behind, and the person knows.
If it goes wrong
Worth offering
- Use recipe write-better-descriptions when agents confuse concepts or the descriptions are vague, redundant or conflicting.
- Offer to update the existing entities that should hold the new property.
- Offer to extract again from the Files that state the new property (recipe extract-files).
- If a View shows types of this Shape, offer to publish the View again (problem view-needs-republish).
Report
Tell the person:- The version number that you published, and its message.
- Each change in the diff, and whether it was additive or breaking.
- How many entities you updated, and which still sit on an older version.
- What waits for approval, who must approve it, and the approval URL.
- That Penumbra did not extract Files again and did not recheck entities.