> For the complete documentation index, see [llms.txt](https://docs.copia.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.copia.io/docs/actions/job-summaries.md).

# Job Summaries

Job summaries let a workflow write formatted [Markdown](https://github.github.com/gfm/) that renders directly on the run page. Instead of scrolling raw log output to find out whether a test passed, you get a readable report — tables, headings, checklists, and diagrams — attached to the job that produced it.

Summaries are written by your workflow steps to a file that Copia captures when the job finishes. They are stored on the Copia server and rendered in the web UI. They are not artifacts, so there is nothing to download and nothing to clean up.

### Why Use Job Summaries

Any time a workflow produces a result a person needs to read, a summary is a better place for it than the log:

* Report unit or validation test results as a pass/fail table rather than console output.
* Show which PLC files a run checked, converted, or flagged.
* Give reviewers an at-a-glance verdict from the pull request checks, without opening the run.
* Publish build metadata — project version, target controller, run duration, file counts.
* Document a process or decision path with a Mermaid diagram.

Without a summary, that information is still in the log, but a reviewer has to know where to look for it.

### Where Summaries Appear

Opening a run without selecting a job shows the **Summary** view: run-level details such as the trigger event, who triggered it, status, and total duration, alongside the workflow graph. The graph shows each job, the dependencies between them, and the overall success rate.

<figure><img src="/files/O3XwD2gMXReoqkcFle5o" alt=""><figcaption></figcaption></figure>

Each panel is labeled with the name of the job that produced it. Panels appear in job completion order, so the job that finished first is listed first.

### Writing a Summary

Each step gets its own summary file. The path is available in the `GITHUB_STEP_SUMMARY` environment variable. Append Markdown to that file and it renders on the run page.

#### On Linux runners

```yaml
- name: Report test results
  run: |
    echo "## Test Results" >> $GITHUB_STEP_SUMMARY
    echo "" >> $GITHUB_STEP_SUMMARY
    echo "| Suite | Passed | Failed |" >> $GITHUB_STEP_SUMMARY
    echo "| --- | --- | --- |" >> $GITHUB_STEP_SUMMARY
    echo "| Safety interlocks | 12 | 0 |" >> $GITHUB_STEP_SUMMARY
    echo "| Conveyor sequencing | 8 | 1 |" >> $GITHUB_STEP_SUMMARY
```

#### On Windows runners

Windows runners default to PowerShell, where the variable is referenced as `$env:GITHUB_STEP_SUMMARY`:

```yaml
- name: Report test results
  shell: powershell
  run: |
    "## Test Results" >> $env:GITHUB_STEP_SUMMARY
    "" >> $env:GITHUB_STEP_SUMMARY
    "| Suite | Passed | Failed |" >> $env:GITHUB_STEP_SUMMARY
    "| --- | --- | --- |" >> $env:GITHUB_STEP_SUMMARY
    "| Safety interlocks | 12 | 0 |" >> $env:GITHUB_STEP_SUMMARY
    "| Conveyor sequencing | 8 | 1 |" >> $env:GITHUB_STEP_SUMMARY
```

{% hint style="info" %}
&#x20;`GITEA_STEP_SUMMARY` is also set and behaves identically, matching the way both `${{ github.xyz }}` and `${{ gitea.xyz }}` are supported in expressions.
{% endhint %}

#### Appending, Overwriting, and Clearing

The summary file behaves like any other file, so redirection controls what ends up in it:

| Operation                             | Result                                   |
| ------------------------------------- | ---------------------------------------- |
| `echo "text" >> $GITHUB_STEP_SUMMARY` | Appends to the step's summary            |
| `echo "text" > $GITHUB_STEP_SUMMARY`  | Replaces everything written by that step |
| `rm $GITHUB_STEP_SUMMARY`             | Clears the step's summary entirely       |

These operations only affect the step that runs them. A step cannot modify or clear another step's summary.

They also only apply while the job is running. Once a step finishes, its summary is uploaded and fixed — a later step cannot revise it, and a re-run produces a separate summary rather than editing the original.

### How Summaries Are Assembled

Understanding the assembly order helps when a summary does not look the way you expected:

1. **Each step is captured separately.** Steps are isolated, so an unclosed code fence or a broken table in one step cannot corrupt the rendering of another.
2. **Steps are concatenated per job.** When the job finishes, all of its step summaries are joined in step order into a single job summary.
3. **Jobs are ordered by completion time.** On the run Summary view, the job that finished first appears first — which is not necessarily the order the jobs are declared in.

### Examples

#### Conditional pass/fail report

Use `if` conditions to write a different summary depending on the outcome of an earlier step:

```yaml
name: Validate PLC Project
on: pull_request

jobs:
  validate:
    runs-on: windows10-S5K
    steps:
      - name: Check out repository
        uses: actions/checkout

      - name: Run validation
        id: validate
        continue-on-error: true
        shell: powershell
        run: ./scripts/validate-project.ps1

      - name: Report success
        if: steps.validate.outcome == 'success'
        shell: powershell
        run: |
          "## Validation passed" >> $env:GITHUB_STEP_SUMMARY
          "" >> $env:GITHUB_STEP_SUMMARY
          "All project checks completed with no findings." >> $env:GITHUB_STEP_SUMMARY

      - name: Report failure
        if: steps.validate.outcome == 'failure'
        shell: powershell
        run: |
          "## Validation failed" >> $env:GITHUB_STEP_SUMMARY
          "" >> $env:GITHUB_STEP_SUMMARY
          "Review the validation log for details." >> $env:GITHUB_STEP_SUMMARY
```

#### Building a summary across multiple steps

Because step summaries are concatenated in order, you can build up a report as the job progresses:

```yaml
jobs:
  build:
    runs-on: windows10-S5K
    steps:
      - uses: actions/checkout

      - name: Start report
        shell: powershell
        run: |
          "# Build Report" >> $env:GITHUB_STEP_SUMMARY
          "" >> $env:GITHUB_STEP_SUMMARY
          "Commit: ``${{ github.sha }}``" >> $env:GITHUB_STEP_SUMMARY

      - name: Compile project
        shell: powershell
        run: |
          ./scripts/compile.ps1
          "## Compile" >> $env:GITHUB_STEP_SUMMARY
          "Completed with no errors." >> $env:GITHUB_STEP_SUMMARY

      - name: Checklist
        shell: powershell
        run: |
          "## Pre-deployment checklist" >> $env:GITHUB_STEP_SUMMARY
          "- [x] Project compiles" >> $env:GITHUB_STEP_SUMMARY
          "- [x] Tag conventions verified" >> $env:GITHUB_STEP_SUMMARY
          "- [ ] Signed off by controls lead" >> $env:GITHUB_STEP_SUMMARY
```

#### Labeling matrix legs

Each matrix leg produces its own panel, so include the matrix value in the content to make the report readable on its own:

```yaml
jobs:
  test:
    runs-on: windows
    strategy:
      matrix:
        controller: [S7-1200, S7-1500]
    steps:
      - uses: actions/checkout@v4
      - name: Report
        shell: powershell
        run: |
          "## ${{ matrix.controller }}" >> $env:GITHUB_STEP_SUMMARY
          "Tests completed for target ${{ matrix.controller }}." >> $env:GITHUB_STEP_SUMMARY
```

#### Mermaid diagrams

[Mermaid](https://mermaid.ai/open-source/intro/index.html) blocks in a summary render as diagrams:

````yaml
- name: Diagram the deployment path
  shell: powershell
  run: |
    "## Deployment path" >> $env:GITHUB_STEP_SUMMARY
    '```mermaid' >> $env:GITHUB_STEP_SUMMARY
    "graph LR" >> $env:GITHUB_STEP_SUMMARY
    "  A[Commit] --> B[Validate]" >> $env:GITHUB_STEP_SUMMARY
    "  B --> C[Stage]" >> $env:GITHUB_STEP_SUMMARY
    "  C --> D[Deploy to line]" >> $env:GITHUB_STEP_SUMMARY
    '```' >> $env:GITHUB_STEP_SUMMARY
````

<figure><img src="/files/nwiHKvWI8SzVTEGLpbj1" alt=""><figcaption></figcaption></figure>

### Supported Formatting

Summaries render GitHub Flavored Markdown, including headings, tables, task lists, fenced code blocks, links, blockquotes, and Mermaid diagrams.

Content is sanitized before rendering. The following are not supported:

* Scripts and any form of interactivity.
* Custom CSS, including `style` and `class` attributes.
* Images from paths inside the workspace. Images must be reachable at a public URL to display.

### Secrets Are Not Masked

{% hint style="danger" %}
**Secrets written into a job summary are rendered as plain text.** Unlike workflow logs, summary content is not passed through secret masking. Anyone who can view the run can read the summary.

Never write a secret, token, password, or connection string into `$GITHUB_STEP_SUMMARY` — including indirectly, such as by echoing an entire environment or dumping a configuration file.
{% endhint %}

If a secret does reach a summary, treat it as exposed: rotate the secret, then remove the summaries from the run as described below.

### Removing Summaries

Summary content can be removed from a completed run without deleting the run itself. On the run **Summary** view, select **Remove Summaries** at the top right of the summary panels.

<figure><img src="/files/nilHmBbadFWB0XyalxmS" alt=""><figcaption></figcaption></figure>

This removes the stored summary content for the run. The run itself, its logs, and its artifacts are unaffected — only the rendered summaries are removed.

Removal is permanent. The content cannot be restored, and re-running the workflow produces new summaries rather than recovering the previous ones.

{% hint style="danger" %}
**Removing summaries applies to the whole run.** Individual job or step summaries cannot be removed on their own.
{% endhint %}

Use this feature when something that should not be printed to a summary is visibile, like a secret. Once the summary is removed, rotate the secret for security purposes.

### Limits

**1 MiB per job.** The combined size of all step summaries in a job is also capped at 1 MiB.

**Over-limit content is truncated, not dropped.** When a summary exceeds the cap, the content is truncated and marked in place with `Job summary truncated: it exceeded the maximum allowed size.` The step and the job both continue normally — an oversized summary never fails a run.

**Summaries are not artifacts.** They are stored on the Copia server and rendered in the UI only. They do not appear in the [Artifacts](/docs/actions/artifacts.md) section, cannot be downloaded, and are not retrievable through the API. If you need the report as a file, write it to disk and upload it with `actions/upload-artifact` in addition to writing the summary.

### Troubleshooting

**The Summary view is empty.** Confirm that a step actually wrote to `GITHUB_STEP_SUMMARY`, and that it used `>>` or `>` rather than printing to standard output. A step that only runs `echo "text"` prints to the log, not the summary.

**A summary is missing on Windows.** PowerShell requires the `$env:` prefix. `$GITHUB_STEP_SUMMARY` on its own resolves to an empty value in PowerShell, so the redirect goes nowhere.

**A table is not rendering.** Markdown tables require a header separator row (`| --- | --- |`) and a blank line before the table starts. Write the blank line explicitly with `echo ""`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.copia.io/docs/actions/job-summaries.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
