reference
Cross-cutting material that governs how work is done, regardless of where.
export reference Voice:
description: How the product speaks to users.
guidance:
Plain and direct. Never cute. Name the object, not the gesture:
"Delete layer", not "Remove this".A reference is a rule that applies everywhere.
The other four definition kinds partition your software: the concept is the whole, domains are regions, components and features are things inside them. A reference cuts across all of it. Voice. Naming. Error style. Commit conventions. How your API is shaped.
It is the catch-all, and it is also — line for line — the highest return of anything in Morphic, because these are the rules you have already explained out loud several times.
guidance — string, required
The rule, and enough of it to apply.
The failure mode here is abstraction. "Be consistent." "Write clear errors." "Keep the API simple." Those are not rules, they are agreements to have the argument later, and an agent handed one will produce something it can defend and you will not like.
Write rules you could be wrong about. Then give examples.
# No. Nobody disagrees, and nobody can act on it.
guidance:
Error messages should be clear and helpful.
# Yes. This decides things.
guidance:
Say what happened, then what to do about it, in that order. One sentence
each.
Name the thing that failed, not the layer that noticed. "Could not read
config.psy" — not "FileSystemAdapter threw".
Never show a stack trace to an end user. Log it, and give them an id.Examples, in pairs
The single most effective thing you can put in a reference is a good/bad pair. They are unambiguous, they are short, and they do not require the reader to share your taste.
export reference Voice:
description: How the product speaks to users.
guidance:
Plain and direct. Never cute, never apologetic, never chatty.
Name the object, not the gesture. Users think about the thing they are
acting on, not the act.
examples:
- "Delete layer" — not "Remove this"
- "Export failed. The disk is full." — not "Oops! Something went wrong :("
- "3 layers selected" — not "You have selected 3 layers"
avoid:
- Exclamation marks
- "Please" and "Sorry"
- Naming our own internals in user-facing text---
name: voice
description: "Reference: How the product speaks to users."
---
# Voice
## Guidance
Plain and direct. Never cute, never apologetic, never chatty.
Name the object, not the gesture. Users think about the thing they are acting
on, not the act.
## Examples
- "Delete layer" — not "Remove this"
- "Export failed. The disk is full." — not "Oops! Something went wrong :("
- "3 layers selected" — not "You have selected 3 layers"
## Avoid
- Exclamation marks
- "Please" and "Sorry"
- Naming our own internals in user-facing text
## Authority
This describes the product as it is meant to work. Where the implementation
disagrees, treat this as correct unless the task is explicitly to change it.examples and avoid are not properties Morphic knows about. They became
sections anyway.
Examples
Naming conventions
use "@psy/morphic"
export reference Naming:
description: Naming conventions across the codebase.
guidance:
Types are nouns. Functions are verbs. Anything that mutates the
document is a Command and its name ends in one.
Prefer the domain's word over the general one. We have layers, not
elements; anchors, not points; a canvas, not a viewport.
examples:
- `MoveLayerCommand` — mutates, so it is a Command
- `flattenLayers()` — a verb, does not mutate
- `LayerStack` — a noun, and the domain's word
avoid:
- `Manager`, `Helper`, `Util`, `Service` as name suffixes. They mean "I could not decide what this is."
- Abbreviations that are not already in the glossary---
name: naming
description: "Reference: Naming conventions across the codebase."
---
# Naming
## Guidance
Types are nouns. Functions are verbs. Anything that mutates the document is a
Command and its name ends in one.
Prefer the domain's word over the general one. We have layers, not elements;
anchors, not points; a canvas, not a viewport.
## Examples
- `MoveLayerCommand` — mutates, so it is a Command
- `flattenLayers()` — a verb, does not mutate
- `LayerStack` — a noun, and the domain's word
## Avoid
- `Manager`, `Helper`, `Util`, `Service` as name suffixes. They mean "I could
not decide what this is."
- Abbreviations that are not already in the glossary
## Authority
This describes the product as it is meant to work. Where the implementation
disagrees, treat this as correct unless the task is explicitly to change it.The Manager/Helper/Util line is the sort of thing that would otherwise be a
review comment every few weeks, forever.
API conventions
export reference ApiConventions:
description: How our HTTP APIs are shaped.
guidance:
Resources are plural nouns. Actions that do not fit CRUD are a POST to
a sub-resource, not a verb in the path.
Every list endpoint is paginated from day one, cursor-based, even when
the collection is small today.
Errors return a stable machine-readable code alongside the human
message. Clients switch on the code; the message is for logs.
examples:
- `POST /invoices/{id}/void` — not `POST /voidInvoice`
- `GET /customers?cursor=…&limit=…` — never offset pagination
- `{ "code": "invoice_already_paid", "message": "…" }`
avoid:
- Verbs in paths
- 200 with an error body
- Breaking a response shape without a versionTesting style
export reference TestingStyle:
description: How tests are written here.
guidance:
A test names the behaviour, not the function. If the function is
renamed the test name should still read correctly.
Assert on observable behaviour, never on internal calls. A test that
breaks on a refactor with no behaviour change is a bug in the test.
One reason to fail per test.
examples:
- `it("keeps layer order across save and load")` — not `it("tests LayerStack.save")`
avoid:
- Mocking anything you own. Mock the network and the clock; nothing else.
- Snapshot tests of anything a human has not readVisual language
export reference VisualLanguage:
description: Spacing, colour and type across the interface.
guidance:
Spacing is a 4px scale. Nothing is ever an arbitrary pixel value.
Colour is semantic, never literal: `--surface-raised`, not
`--grey-200`. A component that names a literal colour has taken a
decision that belongs to the theme.
Two type sizes per panel, maximum.
avoid:
- Hard-coded hex values outside the theme definition
- Shadows for anything other than elevationExtra properties that earn their place
| Property | Use it for |
|---|---|
examples | good/bad pairs — add these before anything else |
avoid | the specific things you keep having to reject |
rationale | why, when the rule looks arbitrary |
exceptions | where the rule genuinely does not apply |
---
name: api-conventions
description: "Reference: How our HTTP APIs are shaped."
---
# ApiConventions
## Guidance
Resources are plural nouns. Actions that do not fit CRUD are a POST to a
sub-resource, not a verb in the path.
Every list endpoint is paginated from day one, cursor-based, even when the
collection is small today.
Errors return a stable machine-readable code alongside the human message.
Clients switch on the code; the message is for logs.
## Examples
- `POST /invoices/{id}/void` — not `POST /voidInvoice`
- `GET /customers?cursor=…&limit=…` — never offset pagination
- `{ "code": "invoice_already_paid", "message": "…" }`
## Avoid
- Verbs in paths
- 200 with an error body
- Breaking a response shape without a version
## Authority
This describes the product as it is meant to work. Where the implementation
disagrees, treat this as correct unless the task is explicitly to change it.exceptions matters more than it looks. A rule with no stated exceptions gets
applied in the one place it should not, and because definitions are normative,
applied confidently.
exceptions:
- Generated files are exempt from the naming rules. They are output, not source.reference or skill?
This is the one real point of confusion in Morphic, and it is worth being precise about, because both are prose telling somebody how to do something.
reference | skill | |
|---|---|---|
| Is | knowledge about the product | instructions for working |
| Answers | "what are the rules here?" | "how do I do this task?" |
| Named by | context | use |
| Voice | declarative — errors name the thing that failed | imperative — read the whole diff first |
| Changes when | the product's conventions change | your process changes |
| Inherits | authority — it is normative | nothing like it |
The rule of thumb: if it would still be true with no AI agent anywhere near the project, it is a reference. Your error message style is a fact about your product. "Read the whole diff before commenting" is a fact about how you would like work done.
Getting it wrong is not catastrophic — both render as loadable skills — but it puts the rule in the wrong place, so it churns for the wrong reasons and gets loaded at the wrong times.
When to write one
The moment you have explained something for the second time.
That is the whole heuristic and it works better than any taxonomy. A rule you have explained twice is a rule you will explain twenty times. Writing it down as a reference takes ten minutes and it is the only definition kind that pays for itself immediately.
References are also the best place to start on an existing codebase, because they require no architectural analysis — just recall of the last few code reviews. See Specifying Software.
When not to write one
- For a rule that applies to one area. That is an
invarianton the domain or the component. - For instructions to an agent. That is a skill.
- For something universally agreed. "Write readable code" is not a rule, it is a mood.
How it renders
---
name: voice
description: "Reference: How the product speaks to users."
---
# Voice
## Guidance
Plain and direct. Never cute, never apologetic, never chatty.
Name the object, not the gesture. Users think about the thing they are acting
on, not the act.
## Examples
- "Delete layer" — not "Remove this"
- "Export failed. The disk is full." — not "Oops! Something went wrong :("
## Avoid
- Exclamation marks
- "Please" and "Sorry"
- Naming our own internals in user-facing text
## Authority
This describes the product as it is meant to work. Where the implementation
disagrees, treat this as correct unless the task is explicitly to change it.Wire it to whatever it governs:
export skill WriteInterfaceCopy:
description: Write or revise user-facing text.
when: Use when adding or changing any string a user will read.
context:
- Voice
prompt:
Write the copy, then read it back as though you were annoyed and in a
hurry. Cut anything that does not survive.Next: What Gets Generated