# Write a practice

State a positive standard that a review can judge within a clear evidence boundary. Describe required behavior once. Keep guidance separate from the criteria.

## Define the standard

1. Enter the practice's name and stable identifier.
2. Select its kind of work.
3. Write what the work must do to meet the practice.
4. Describe the facts that make the practice inapplicable.
5. Describe the consequence that justifies each problem's severity.

An optional improvement is not a problem. A broad claim needs evidence for its full boundary. A search can prove absence only within a complete bounded corpus. The [outcome contract](/contributor/practice-feedback-language.md#observation-outcomes) owns the four outcomes.

## Select review evidence

Review on selects events. When selects their recorded state for automatic review. Applies when governs every origin, including a request.

The server checks these conditions against captured evidence before the practice script runs. If every condition is proven false, the observation is Does not apply with your Otherwise explanation. Incomplete or unavailable evidence cannot prove a condition false. Required capture failure withholds the practice without an observation. Issues offer no applicability conditions.

A request does not bypass source access, scope or consent.

About selects Author, Reviewer, Assignee or Merger. Choose The work when the observation concerns no developer. A selected role must resolve to one eligible human account. A missing or ambiguous role withholds the practice instead of choosing a person.

Reads retains the source contract and required, complete or optional sources.

Contract 3.0.0 gives CI evidence its own source, `scm.pull-request.checks`. Read its `checks.json` for `head_checks`, `head_check_runs`, and `merge_state_status`. Read `review_decision` from the review discussion source, `scm.review-threads`, in `review_threads.json`. These fields are absent from the pull request core record. The [source contract](/contributor/item-source-contract.md#source-catalog) defines unknown observations and unfinished runs.

The upgrade migrates current definitions and comparison bases, including customized practices, to contract 3.0.0. It preserves their criteria and scripts. Update custom references to the old record paths before reviews resume.

Required capture failure never becomes a semantic outcome. Do not list optional evidence as sufficient proof of exhaustive coverage.

The pull request details include the check runs of the reviewed commit when Hephaestus has read them. Only GitHub supplies them. Write the practice so that missing check runs give Could not determine, never Not met. The [source contract](/contributor/item-source-contract.md#source-catalog) owns this rule.

To review a pull request again when its checks finish, select **Checks finished** under Review on. It means that every check GitHub had listed at that time had ended. A workflow or a status that starts later can add checks. A re-run on the same push starts a new review when its checks finish, even if their results match.

If the checks never finish, or the push has none, no review starts for **Checks finished**. Add **Opened**, **Ready** or **Synchronized** to the practice if it must always run.

## Choose who reviews

Reviewed by has three choices:

* Hephaestus: automated review within the declared evidence boundary.
* People: human review, with the reason automation cannot decide.
* Nobody: guidance without automated review.

Keep the human reason and known limits with this choice. Do not duplicate them in a second rubric. Feedback mode is a separate delivery setting. Off does not stop eligible observation recording.

## Add a script and scan support

A null Script uses the built-in script. A custom script can prepare model review or decide from exact captured records. The [script guide](/admin/practice-scripts.md) owns its author contract and tests. An invalid custom script never falls back silently.

Scan support declares selected files and context explicitly. It is available only for practices with a valid repository-state form. A duty at a change event cannot gain a scan form by ignoring that event. A scan observation concerns the file and has no developer.

## Write a practice for a technology

A practice has no technology field. The Hephaestus defaults use three patterns for a standard that depends on a technology.

### Gate one platform by changed paths

The practices of the **Building iOS apps well** group concern Swift code only. Each one applies when a changed path matches `**/*.swift`. A complete change with no Swift file gets Does not apply. Incomplete change evidence keeps the practice eligible.

### Share one practice with leads for each language

**Handle errors instead of swallowing them** applies to code in every language. Its script has a table of constructs for each language that it names. A match is a lead for the review, not an observation. A file in another language gets no lead, and the review still decides. The [script guide](/admin/practice-scripts.md#test-a-script-locally) owns how to test these tables.

### Make a course standard stricter in the workspace

Adopt the default practice in the workspace. Then edit its criteria and save it. For example, a course can require a unit test for each changed function. Saving creates a new practice version, as [Save or reset](#save-or-reset) describes. Later catalog changes arrive as offers that you can accept or decline.

### No practice variants

Do not create a copy of one practice for each technology. Copies of one standard drift apart, and their observations stop being comparable. [ADR 0050](https://github.com/hephaestus-build/Hephaestus/blob/main/docs/decisions/0050-one-practice-standard-one-outcome.md) keeps one standard for each practice. Hephaestus also does not detect the technology stack of a repository.

Reopen this decision only when one of these conditions occurs:

* One standard needs different criteria for each technology, and neither a path gate nor per-language leads can state the difference.
* Workspaces keep several local copies of one default practice, one for each technology.

## Write guidance

Why it matters explains the practice's purpose. What good looks like describes work that meets it. Going well describes what the developer keeps doing when supported observations establish that pattern. Guidance does not add a new criterion or change the evidence standard.

## Add a visual and a guide

A practice can have two optional fields for the developer:

* **Visual** is one SVG picture and its description. The developer's practice panel shows it between **Why it matters** and **What good looks like**.
* **Guide** is a longer explanation in Markdown, with up to 4 SVG figures. The developer opens it in the **Guide** tab of the practice panel.

Both fields are developer guidance. They do not change how the practice is reviewed. Hephaestus receives the descriptions and the text of the guide, but not the pictures. Thus, a description must give the full meaning of its picture.

Add a visual only when it shows the idea better than a sentence. The size of a change and an order of steps are examples.

Both fields are part of the definition. [Save or reset](#save-or-reset) applies to them.

### Add a visual

1. Open the practice in the practice editor.
2. In **Visual**, select **Upload SVG** and choose an SVG file. You can also paste the markup into **SVG markup**.
3. In **Description \***, say what the picture means. Do not describe the shapes or the colors.
4. Check the **Light theme** and **Dark theme** previews.
5. Save the practice.

To remove the visual, select **Remove** in **Visual**. Then save the practice.

### Add a guide

1. In **Guide**, write the text in **Guide text** in Markdown.
2. To add a figure, put the cursor where the figure must show.
3. Select **Add figure** and choose an SVG file. The editor adds the line `![Describe the figure](figures/<name>.svg)` at the cursor.
4. Replace "Describe the figure" with what the figure means. Do not describe the shapes or the colors.
5. Select **Preview** to check the text and the figures.
6. Save the practice.

To remove a figure, select **Remove** beside the figure. The editor also removes the lines that show the figure. To remove the guide, select **Remove guide**. Then save the practice.

A link in a guide opens in a new tab. The guides of the Hephaestus defaults use four headings: **How to do it**, **When it does not apply**, **Common mistakes**, and **Sources**. Your guide can use other headings.

### What Hephaestus accepts

The server checks the visual, the guide, and each figure when you save. If it refuses the save, its message names the element, the attribute, or the limit. The webapp cleans the markup again before it shows the picture.

| Rule               | Limit                                                                                                                                                            |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Root element       | `<svg xmlns="http://www.w3.org/2000/svg" viewBox="…">`                                                                                                           |
| File size          | 64 KB or less for each SVG                                                                                                                                       |
| Elements           | `svg`, `g`, `path`, `rect`, `circle`, `ellipse`, `line`, `polyline`, `polygon`, `text`, `tspan`, `title`, `desc`                                                 |
| Attributes         | Geometry and presentation only. The list follows this table.                                                                                                     |
| Attribute values   | Letters, digits, spaces, and the characters `#` `.` `,` `%` `+` `(` `)` `/` `-` `_`. Thus, a value cannot contain a `url(...)` reference, a quote, or an escape. |
| Not accepted       | Ids, the `style` attribute and element, links, a DOCTYPE, scripts, images, CDATA sections, processing instructions, and comments that contain `<` or `>`         |
| Visual description | 1 to 300 characters                                                                                                                                              |
| Guide text         | Markdown with no HTML, 12,000 characters or fewer                                                                                                                |
| Links in a guide   | Web addresses that start with `https://` or `http://`                                                                                                            |
| Figures            | 4 or fewer for each guide. A figure name has lowercase letters, digits, and single hyphens.                                                                      |
| Images in a guide  | Only the guide's own figures, as `![description](figures/<name>.svg)`. The text shows each figure, with a description.                                           |

The accepted attributes are: `viewBox`, `width`, `height`, `preserveAspectRatio`, `version`, `x`, `y`, `x1`, `y1`, `x2`, `y2`, `cx`, `cy`, `r`, `rx`, `ry`, `d`, `points`, `dx`, `dy`, `transform`, `class`, `fill`, `fill-rule`, `fill-opacity`, `clip-rule`, `stroke`, `stroke-width`, `stroke-linecap`, `stroke-linejoin`, `stroke-miterlimit`, `stroke-dasharray`, `stroke-dashoffset`, `stroke-opacity`, `opacity`, `font-size`, `font-weight`, `font-style`, `text-anchor`, `dominant-baseline`, `letter-spacing`, `vector-effect`, `role`, `aria-hidden`, `focusable`, and `xml:space`.

Most drawing tools add ids, styles, or gradients. Remove them before you upload the file. Without ids, a picture cannot use markers, gradients, masks, filters, or clip paths. Draw an arrowhead as a small filled triangle.

### Colors in light and dark mode

A `pv-*` class gives a shape a color of the app theme. The color changes with the theme. Thus, one file works in the light theme and in the dark theme.

| Class                 | Color                                     |
| --------------------- | ----------------------------------------- |
| `pv-fill-ink`         | Fill with the main text color             |
| `pv-fill-muted`       | Fill with the secondary text color        |
| `pv-fill-surface`     | Fill with the panel background            |
| `pv-fill-accent`      | Fill with the accent color                |
| `pv-fill-accent-soft` | Fill with the accent color at 15% opacity |
| `pv-stroke-ink`       | Stroke with the main text color           |
| `pv-stroke-muted`     | Stroke with the secondary text color      |
| `pv-stroke-line`      | Stroke with the border color              |
| `pv-stroke-accent`    | Stroke with the accent color              |
| `pv-mono`             | The code font of the app                  |

`pv-mono` sets a font, not a color. Use it for one code token in a label of size 15.

[Practice visuals and guides](/contributor/practice-visuals.md#color) gives the meaning of each class.

Set `fill="none"` on a shape that has only a stroke.

A visual with no `pv-*` class keeps its own colors. The panel shows it on a light surface in both themes. Thus, a visual from any drawing tool works without the classes.

### Start from a template

Each starter template uses only accepted markup and `pv-*` classes. Each one draws a composition pattern with placeholder labels:

* [Contrast pair](/assets/files/practice-visual-template-9d382e2f940c8063a79a252bd1e5fc1b.svg): the work without the practice on the left, and the same work with it on the right. Use it unless a fork or a sequence fits better.
* [Fork](/assets/files/practice-visual-template-fork-2fba47ebbbfceabe70c2ecee68f33d1a.svg): one event, then the lapse on top and the practice below.
* [Sequence](/assets/files/practice-visual-template-sequence-0fce816d346e2c966bb933aabad8df80.svg): three steps in order, for a figure in a guide. A visual uses it only to compare two orders, as two rows. [Sequence](/contributor/practice-visuals.md#sequence) gives the layout.

1. Save a copy of a template.
2. Open the copy in a text editor or a drawing tool.
3. Replace each placeholder label.
4. Move, add, or delete shapes.
5. Set the height of the viewBox to the bottom of the lowest shape.
6. Upload the result in **Visual**.

### Draw a visual with an AI assistant

You can ask an AI assistant to draw a visual.

1. Copy the prompt below.
2. Replace each value in angle brackets.
3. Send the prompt to the AI assistant, with the [starter template](#start-from-a-template) of the layout attached.
4. Make sure that the picture adds no requirement to the practice criteria.
5. Upload the SVG in **Visual**.
6. Enter the description.

```
Draw one SVG picture for a software engineering practice. Follow every rule below.



Practice: <name of the practice>

Why it matters: <text of Why it matters>

What good looks like: <text of What good looks like>

The one idea that the picture must show: <one sentence>

Layout: <one of: contrast pair | fork | sequence (two rows that compare two orders)>



Start from the attached starter template of the layout. Keep its coordinates. Change only the labels and the one part that differs, and delete what the idea does not need.



Rules for the file:

- Start with <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 H">, where H is the bottom of the lowest shape, at most 320. Do not set width or height.

- Draw to the edges of the canvas: the first title at the top, the outermost shapes at x 0 and x 640. In a fork, the outcome labels end the picture and reach toward x 640. Leave no empty area larger than about a sixth of the canvas.

- Put panes, frames, nodes, gutters, and content tops on a grid of 8. Keep the line heights, pitches, radii, and baselines of the template. Inset a stroked shape by half its stroke width.

- Use only these elements: svg, g, path, rect, circle, ellipse, line, polyline, polygon, text, tspan, title, desc.

- Use only these attributes: x, y, width, height, rx, ry, cx, cy, r, x1, y1, x2, y2, d, points, dx, dy, transform, class, fill, stroke, stroke-width, stroke-linecap, stroke-linejoin, stroke-dasharray, font-size, font-weight, text-anchor.

- Do not use id, style, href, url(...), opacity, gradients, filters, markers, masks, images, scripts, or a DOCTYPE.

- Color every shape and every text with one of these classes, not with a color value: pv-fill-ink, pv-fill-muted, pv-fill-surface, pv-fill-accent, pv-fill-accent-soft, pv-stroke-ink, pv-stroke-muted, pv-stroke-line, pv-stroke-accent. Add the class pv-mono to a text that is one code token.

- Accent (pv-*-accent) means only what the practice asks for. Use it for one meaning, on the practice side only.

- Muted (pv-*-muted) means context, the lapse, and a missing part. Ink (pv-*-ink) means titles and names. pv-fill-accent-soft fills only a node or region that holds the accent. pv-fill-surface fills the inside of an outlined shape. Use pv-stroke-line for nothing that matters.

- Accent and muted have about the same lightness. Give every accent mark a shape or a position that differs too. A label alone is too small to read on a phone.

- Use fill="none" on a shape that has only a stroke.

- Do not set a font family. Use font-size 16 and font-weight 600 for titles, font-size 15 for labels, and no other size. Use weight 600 for one label only: the one that names what the practice asks for.

- Use 24 words or fewer in the whole picture, in sentence case, with no period.

- Show the difference as one short example on each side (6 words or fewer, or one code token with the class pv-mono), not as colored bars.

- Draw a line of code as a bar 10 high with rx 3, and a line of prose as a bar 6 high. Draw one piece of work as a frame: rx 8, pv-fill-surface, pv-stroke-muted, stroke-width 1.5. Never put a frame inside a frame, and never draw a box around a group of shapes.

- Write the part that the practice asks for as its example in accent text, and the lapse as its example in muted text, at the same place in both panes. Put no rule or other mark next to an example. Draw a missing part as a dashed muted outline with a muted label that names what is missing, such as "No test".

- Make every mark explain itself. Name each piece of work with a word, such as "Pull request" or "Issue #57". Never draw a dot, a tick, or a glyph with no word next to it.

- Draw an arrow as one line path and one small filled triangle path. Use arrows only for order, cause, or flow.

- In a sequence, draw two rows: the lapse order on top, the practice order below. Put the row titles at baselines 16 and 132.

- In a sequence, move the marks of each row 32 down, below its title. Delete the template's detail labels, and set H to 200.

- In a sequence of two steps, use columns 304 wide at x 0 and x 336. Only the practice row has the solid accent marker.

- Draw a person only as a filled circle of radius 8 with its role as a label, such as "Reviewer", never as a face or a figure. Do not draw mascots, logos, emoji, or decoration. Do not animate.

- Do not show a number, a limit, or a threshold that the practice text does not state.

- Keep the file smaller than 64 KB.



Then write one description of 250 characters or fewer (Hephaestus accepts up to 300), in 1 or 2 sentences. Say what the picture means, in the order of the picture. Do not name colors or shapes.

Return only the SVG markup and the description.
```

## Save or reset

Saving a changed definition creates a fixed practice version. Earlier observations retain their original definition. A name, group or guidance change does not change the review standard digest. Reuse still requires the exact practice version and method. Reset removes local customization through the catalog comparison. Check the displayed changes before resetting.
