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 loginif you want to use your collective name in the reportnamefield — 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-compliancethat reads each resource output, checks for requiredenvandownertags, and flags any resources missing them. Label itcomplianceandgovernance.
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-debugSee 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 syncThe 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, ownerAdd --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-complianceReport: @mycollective/tag-compliance
Description: Check resources for required tags
Scope: method
Labels: compliance, governanceWrite a workflow-scope report
Create a workflow-scope report called
@mycollective/step-summarythat 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-allNote
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 complianceSkip all reports for a quick run:
$ swamp model method run prod-servers sync --skip-reportsNote
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.tsFile paths are relative to extensions/reports/ within the extension root. See
Create and Publish for the full
extension publishing workflow.