Skip to main content

CREATE A REPORT

This guide shows you how to write a custom report, wire it into model definitions and workflows, and retrieve the output.

Prerequisites

  • A swamp repository (swamp repo init)
  • At least one model definition with data produced by a method run
  • Optional: swamp auth login if you want to use your collective name in the report name field — without it, the name is not validated

Write a method-scope report

If you are using an AI agent, describe the report you need:

Create a method-scope report called @mycollective/tag-compliance that reads each resource output, checks for required env and owner tags, and flags any resources missing them. Label it compliance and governance.

Tip

The report logic depends on the shape of your model's data. Inspect it with swamp data get <model> <name> --json before writing the report or including the shape in your prompt.

The agent creates extensions/reports/tag_compliance.ts:

export const report = {
  name: "@mycollective/tag-compliance",
  description: "Check resources for required tags",
  scope: "method" as const,
  labels: ["compliance", "governance"],

  async execute(context) {
    const requiredTags = ["env", "owner"];
    const violations = [];

    for (const handle of context.dataHandles) {
      const content = await context.dataRepository.getContent(
        context.modelType,
        context.modelId,
        handle.name,
        handle.version,
      );
      if (!content) continue;

      const data = JSON.parse(new TextDecoder().decode(content));
      const tags = data.tags ?? {};
      const missing = requiredTags.filter((t) => !(t in tags));
      if (missing.length > 0) {
        violations.push({ resource: handle.name, missingTags: missing });
      }
    }

    const compliant = violations.length === 0;
    const checked = context.dataHandles.length;

    const markdown = compliant
      ? `## Tag Compliance\n\nAll ${checked} resources have required tags.`
      : `## Tag Compliance\n\n${violations.length} of ${checked} resources missing required tags:\n\n${
        violations
          .map((v) =>
            `- **${v.resource}**: missing ${v.missingTags.join(", ")}`
          )
          .join("\n")
      }`;

    return {
      markdown,
      json: { compliant, totalChecked: checked, violations },
    };
  },
};

See the Report reference for the full ReportContext and ReportOutput fields.

Wire the report into a model definition

Add the report to a model definition's reports block so it runs after method execution:

reports:
  require:
    - "@mycollective/tag-compliance"

To restrict the report to specific methods, use the object form:

reports:
  require:
    - name: "@mycollective/tag-compliance"
      methods:
        - sync
        - update
  skip:
    - verbose-debug

See Model Definitions — reports for the full ReportSelection schema.

Test the report

Run a method on the model to trigger the report:

$ swamp model method run prod-servers sync

The report runs after the method completes and prints its output:

── Report: @mycollective/tag-compliance ──────────────────────
## Tag Compliance

2 of 2 resources missing required tags:

- **web-1**: missing env, owner
- **api-1**: missing env, owner
──────────────────────────────────────────────────────────────

View report output

Retrieve the report with swamp report get:

$ swamp report get @mycollective/tag-compliance --model prod-servers
──────────────────────────────────────────────────────────────
  @mycollective/tag-compliance  |  Model: prod-servers  |  Scope: method  |  v1
──────────────────────────────────────────────────────────────
## Tag Compliance

2 of 2 resources missing required tags:

- **web-1**: missing env, owner
- **api-1**: missing env, owner

Add --json for the structured data:

$ swamp report get @mycollective/tag-compliance --model prod-servers --json
{
  "reportName": "@mycollective/tag-compliance",
  "reportScope": "method",
  "modelName": "prod-servers",
  "version": 1,
  "markdown": "## Tag Compliance\n\n...",
  "json": {
    "compliant": false,
    "totalChecked": 2,
    "violations": [
      { "resource": "web-1", "missingTags": ["env", "owner"] },
      { "resource": "api-1", "missingTags": ["env", "owner"] }
    ]
  }
}

Use swamp report describe to inspect a report's metadata:

$ swamp report describe @mycollective/tag-compliance
Report: @mycollective/tag-compliance
Description: Check resources for required tags
Scope: method
Labels: compliance, governance

Write a workflow-scope report

Create a workflow-scope report called @mycollective/step-summary that summarizes all step outcomes in a markdown table showing step name, model, and status.

The agent creates extensions/reports/step_summary.ts:

export const report = {
  name: "@mycollective/step-summary",
  description: "Summarize workflow step outcomes",
  scope: "workflow" as const,
  labels: ["summary"],

  async execute(context) {
    const steps = context.stepExecutions;
    const succeeded = steps.filter((s) => s.status === "succeeded").length;
    const failed = steps.filter((s) => s.status === "failed").length;

    const rows = steps
      .map(
        (s) =>
          `| ${s.stepName} | ${s.modelName}${s.methodName} | ${s.status} |`,
      )
      .join("\n");

    const markdown = [
      `## Step Summary for ${context.workflowName}`,
      "",
      `${succeeded} succeeded, ${failed} failed out of ${steps.length} steps.`,
      "",
      "| Step | Model | Status |",
      "| ---- | ----- | ------ |",
      rows,
    ].join("\n");

    return {
      markdown,
      json: {
        workflowName: context.workflowName,
        status: context.workflowStatus,
        totalSteps: steps.length,
        succeeded,
        failed,
      },
    };
  },
};

Wire a report into a workflow

Add a reports block to the workflow YAML:

name: sync-all
reports:
  require:
    - "@mycollective/step-summary"
jobs:
  - name: main
    steps:
      - name: sync-prod
        ...

Run the workflow and the report appears after all steps complete:

$ swamp workflow run sync-all
── Report: @mycollective/step-summary ────────────────────────
## Step Summary for sync-all

1 succeeded, 0 failed out of 1 steps.

| Step      | Model               | Status    |
| --------- | ------------------- | --------- |
| sync-prod | prod-servers → sync | succeeded |
──────────────────────────────────────────────────────────────

Retrieve it with swamp report get using --workflow:

$ swamp report get @mycollective/step-summary --workflow sync-all

Note

Workflow-level reports settings take precedence over definition-level settings, which take precedence over model-type defaults. See Workflows — reports for the full schema.

Filter reports at runtime

CLI flags let you control which reports run without editing YAML:

Flag Effect
--skip-reports Skip all reports
--skip-report <name> Skip a specific report (repeatable)
--report <name> Run only this report (repeatable)
--report-label <label> Run only reports with this label
--skip-report-label <label> Skip reports with this label

Run only compliance-labeled reports:

$ swamp model method run prod-servers sync --report-label compliance

Skip all reports for a quick run:

$ swamp model method run prod-servers sync --skip-reports

Note

Reports listed in reports.require survive --skip-report <name> — they can only be suppressed by --skip-reports or by adding the name to reports.skip in the definition or workflow YAML.

Package the report

Declare reports in your extension's manifest:

reports:
  - tag_compliance.ts
  - step_summary.ts

File paths are relative to extensions/reports/ within the extension root. See Create and Publish for the full extension publishing workflow.