Skip to content

feat(#6966): add a completed reference agent and an authoring skill - #1167

Open
waynesun09 wants to merge 9 commits into
mainfrom
agent-6966-agent-templates
Open

feat(#6966): add a completed reference agent and an authoring skill#1167
waynesun09 wants to merge 9 commits into
mainfrom
agent-6966-agent-templates

Conversation

@waynesun09

Copy link
Copy Markdown
Member

What

The two things fullsend agent new hands off to:

  • examples/link-check/ — a complete agent generated by that command and then finished. A review-role agent that reports Markdown links in changed docs which do not resolve.
  • skills/authoring-custom-agents/ — the procedure for completing a generated skeleton.

Why examples/ and not the fleet directories

harness/, agents/, schemas/ and scripts/ are consumed by URL via agent add, so anything placed there reads as a first-class agent. Per the #631 discussion, custom and community agents are not mixed with tier-one agents. The example lives in its own subtree and is not registered in config.yaml — nothing dispatches it.

Being an example is not a reason to be unchecked

It exists to be copied, so an unfilled placeholder or an unsafe post-script in it is exactly as harmful as in a real agent.

skillsaw did not lint examples/ at all. I verified this rather than assuming: planting a <!-- FILL IN --> marker and a TODO: into the example's agent definition and running make lint gave Warnings: 0 / ✓ All checks passed. Adding examples/**/agents/*.md to content-paths fixes it — the identical plant now gives Warnings: 1 and make lint exits 1 under --strict.

The post-script is tested. scripts/example-link-check-test.sh, wired into make test, covers 16 cases against untrusted model output:

  • field allowlist, and non-string values refused rather than coerced ({"summary": {"nested": true}})
  • status enum, required fields, the 200-char summary cap
  • comment truncation at 16384 rather than rejection
  • ISSUE_URL validation: a foreign host (https://evil.example.com/...) and a path-traversal attempt (.../pull/99/../../x) are both refused
  • missing result file, missing required environment

All run with POST_LINK_CHECK_DRY_RUN=1, so nothing is ever posted.

How to test

make lint          # skillsaw --strict, now including examples/
make test          # includes scripts/example-link-check-test.sh
make check-bundle
bash scripts/example-link-check-test.sh   # the 16 cases on their own

To confirm the example is a loadable agent, from a fullsend checkout:

fullsend lock link-check --fullsend-dir examples/link-check --offline

Validated commands

# Command Executed Result
1 fullsend agent new link-check --role review --on pr-opened --slug fullsend-ai-link-check --no-register yes generated the tree committed here, verbatim apart from the finished prompt
2 bash scripts/example-link-check-test.sh yes 16/16 pass
3 make lint yes 0 errors, 0 warnings, Grade A
4 make lint with a planted FILL IN + TODO yes Warnings: 1, exit 1 — proves the new scope works
5 make check-bundle yes clean (the example's post-script is standalone, not a .src.sh bundle)
6 make test yes see the pre-existing flake note below
7 fullsend lock link-check --fullsend-dir examples/link-check --offline yes loads and validates

Documented but not executed: a real dispatch of the example agent. That needs GCP credentials, a sandbox image and a live pull request, and the post-script's non-dry-run path comments on a real work item.

Pre-existing make test flake, not from this change

scripts/harness-jira-test.sh reports 2–4 failures per run, non-deterministically — yq | grep -q returns 141 under set -o pipefail. Three consecutive runs of the unchanged test on this branch gave 3, then 4, then 2 failures. The values it reports as missing are present in harness/triage.yaml:

$ yq '.overlays[] | select(.when | test("jira")) | .env.runner.JIRA_TOKEN' harness/triage.yaml
${JIRA_TOKEN}

This branch touches neither harness/ nor that test.

Notes

@waynesun09
waynesun09 requested a review from a team as a code owner September 3, 2026 16:40
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add reference link-check agent and custom-agent authoring skill

✨ Enhancement 📝 Documentation 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Adds a complete, isolated link-check review agent as a loadable custom-agent reference.
• Documents the procedure for completing generated agents while preserving their output contracts.
• Extends linting and tests to validate examples and harden untrusted result handling.
Diagram

sequenceDiagram
  actor Event as PR Event
  participant Harness as Agent Harness
  participant Agent as Link Checker
  participant Schema as Result Schema
  participant Result as Result JSON
  participant Post as Post Script
  participant GitHub as GitHub
  Event->>Harness: PR opened or synced
  Harness->>Agent: Run read-only review
  Agent->>Schema: Validate contract
  Agent->>Result: Write structured result
  Harness->>Post: Run trusted processing
  Post->>Result: Read allowlisted fields
  alt findings or error
    Post->>GitHub: Upsert sticky comment
  else ok
    Post-->>Harness: Skip comment
  end
Loading
High-Level Assessment

The chosen approach is appropriate: keeping the example outside fleet directories prevents accidental registration while retaining a complete, loadable package that users can inspect. A documentation-only sample would drift without executable checks, while registering it as a fleet agent would misrepresent its support tier; linting and dry-run post-script tests provide the right enforcement boundary.

Files changed (14) +624 / -1

Enhancement (3) +197 / -0
link-check.mdDefine the reference link-check agent +79/-0

Define the reference link-check agent

• Provides a complete review-agent prompt for identifying unresolved local Markdown links in changed documentation. It specifies deterministic decisions, a strict JSON output contract, and a no-mutation boundary.

examples/link-check/agents/link-check.md

link-check-result.schema.jsonDefine the link-check result contract +33/-0

Define the link-check result contract

• Requires string-valued 'status', 'summary', and 'comment' fields, rejects additional properties, and enforces status and length constraints.

examples/link-check/schemas/link-check-result.schema.json

post-link-check.shSafely publish link-check findings +85/-0

Safely publish link-check findings

• Validates untrusted result fields, limits output sizes, strictly parses GitHub issue URLs, and skips successful results. Findings and errors are published through the sticky-comment primitive, with a dry-run mode for testing.

examples/link-check/scripts/post-link-check.sh

Tests (2) +167 / -0
MakefileRun the example post-script test suite +1/-0

Run the example post-script test suite

• Adds the link-check example's shell tests to the standard 'script-test' target.

Makefile

example-link-check-test.shTest untrusted link-check result processing +166/-0

Test untrusted link-check result processing

• Adds dry-run coverage for valid results, malformed JSON, invalid types and statuses, required fields, size limits, hostile URLs, missing files, and missing environment variables.

scripts/example-link-check-test.sh

Documentation (2) +126 / -0
README.mdDocument the reference-agent collection +41/-0

Document the reference-agent collection

• Explains why examples are separate from fleet agents, how to use them during custom-agent authoring, and which lint, test, and loading guarantees they must satisfy.

examples/README.md

SKILL.mdAdd the custom-agent authoring procedure +85/-0

Add the custom-agent authoring procedure

• Guides authors through completing generated prompts while keeping tools, schemas, post-scripts, and decision boundaries aligned. It also documents offline loading and pre-commit validation requirements.

skills/authoring-custom-agents/SKILL.md

Other (7) +134 / -1
.skillsaw.yamlLint example agent definitions +9/-1

Lint example agent definitions

• Adds example agent Markdown files to skillsaw content discovery. This makes placeholders and stale TODOs in copyable examples fail strict linting.

.skillsaw.yaml

link-check.yamlConfigure the link-check agent harness +49/-0

Configure the link-check agent harness

• Defines the review role, pull-request triggers, model, sandbox resources, environment mapping, and trusted post-script. The trigger excludes forked pull requests and supports opened, synchronized, and ready transitions.

examples/link-check/harness/link-check.yaml

base.yamlAdd the example sandbox policy +22/-0

Add the example sandbox policy

• Restricts filesystem access and runs the agent as the sandbox user. Network permissions remain delegated to provider profiles.

examples/link-check/policies/base.yaml

fullsend-github-ro.yamlRestrict GitHub access to read-only operations +19/-0

Restrict GitHub access to read-only operations

• Allows 'gh' and Node access only to GitHub endpoints under an enforced read-only profile.

examples/link-check/profiles/fullsend-github-ro.yaml

fullsend-vertex-ai.yamlConfigure Vertex AI inference access +23/-0

Configure Vertex AI inference access

• Defines the allowed Anthropic and Google API endpoints and binaries required for model inference.

examples/link-check/profiles/fullsend-vertex-ai.yaml

github-ro.yamlDeclare the read-only GitHub provider +6/-0

Declare the read-only GitHub provider

• Binds the example harness to the read-only GitHub profile with the required placeholder credential configuration.

examples/link-check/providers/github-ro.yaml

vertex-ai.yamlDeclare the Vertex AI provider +6/-0

Declare the Vertex AI provider

• Binds the example harness to the Vertex AI inference profile with the required placeholder credential configuration.

examples/link-check/providers/vertex-ai.yaml

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 3, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 4:42 PM UTC · Ended 5:24 PM UTC

Commit: a2b1f10 · View workflow run →

@qodo-code-review

qodo-code-review Bot commented Sep 3, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (1)

Grey Divider


Action required

1. Deleted documentation causes errors ✓ Resolved 🐞 Bug ≡ Correctness
Description
Deleted .md paths returned by the filename diff survive the extension filter, but the head
checkout no longer contains those files for link extraction. A deletion-only documentation PR can
therefore produce an error instead of reporting that it introduces no broken links.
Code

examples/link-check/agents/link-check.md[R31-35]

+2. Keep only the changed files ending in `.md`. If there are none, write
+   `status: "ok"` with the summary `No documentation changes` and stop.
+
+3. For each remaining file, extract every Markdown link target — the target in
+   `[text](target)` and in `[ref]: target` definitions. Classify each:
Relevance

●●● Strong

Deleted Markdown paths require explicit handling before head-checkout extraction; otherwise
deletion-only PRs can fail incorrectly.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The checkout is at the PR head, while the command collects changed names without status and the only
filter is the .md suffix. The next step requires extracting links from every retained path and
provides no deleted-file handling.

examples/link-check/agents/link-check.md[16-17]
examples/link-check/agents/link-check.md[21-35]
examples/link-check/agents/link-check.md[50-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The prompt does not distinguish deleted Markdown files from files present at the PR head, yet instructs the agent to read every selected path. Retrieve file status and skip deleted paths before link extraction.

## Issue Context
The sandbox checkout is explicitly at the pull request head, where deleted files are unavailable.

## Fix Focus Areas
- examples/link-check/agents/link-check.md[16-17]
- examples/link-check/agents/link-check.md[21-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unchanged links become findings ✓ Resolved 🐞 Bug ≡ Correctness
Description
The agent obtains only changed filenames and then checks every link in each modified Markdown file,
so a pre-existing broken link untouched by the PR is reported as a new finding. This contradicts the
agent's stated scope of links added or changed by the pull request.
Code

examples/link-check/agents/link-check.md[R24-25]

+   gh pr view "$ISSUE_URL" --json number,baseRefName,headRefName
+   gh pr diff "$ISSUE_URL" --name-only
Relevance

●●● Strong

Changed-file-only scope misses unchanged links; this is a direct correctness bug in the agent
instructions.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The prompt defines its scope as links added or changed by the PR, but --name-only provides no
changed-line information. It subsequently extracts every link from selected files and reports every
nonexistent target, with no test for whether the link was changed.

examples/link-check/agents/link-check.md[8-10]
examples/link-check/agents/link-check.md[21-35]
examples/link-check/agents/link-check.md[47-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The link-check agent uses a filename-only diff and then checks every link in each changed Markdown file. Restrict findings to link targets introduced or modified by the pull request.

## Issue Context
The agent's stated purpose is to report links added or changed by the PR, not pre-existing broken links in otherwise modified files.

## Fix Focus Areas
- examples/link-check/agents/link-check.md[21-48]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Protected paths require human approval 📜 Skill insight § Compliance
Description
This PR modifies protected scripts/ and skills/ paths, so it must receive human governance
review even though the linked issue and PR description explain the changes. Automated approval is
prohibited for these paths.
Code

scripts/example-link-check-test.sh[1]

+#!/usr/bin/env bash
Relevance

●● Moderate

Protected-path governance appears relevant, but similar requests for explicit protected-path
authorization were recently rejected.

PR-#753
PR-#631

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1538392 explicitly designates scripts/ and skills/ as protected paths and
requires a finding whenever they are modified. The PR adds both a root-level test script and an
authoring skill.

scripts/example-link-check-test.sh[1-12]
skills/authoring-custom-agents/SKILL.md[1-13]
Skill: pr-review


View high (1)
4. Google API bypass unauthorized ✗ Dismissed 📜 Skill insight ⛨ Security
Description
The new Vertex AI profile disables credential inspection for every *.googleapis.com endpoint
without explicit issue or ADR authorization. The repository’s primary profile limits this
security-sensitive bypass to api.anthropic.com, so the broader permission exceeds the established
least-privilege configuration.
Code

examples/link-check/profiles/fullsend-vertex-ai.yaml[20]

+    allow_uninspected_credentials: true
Relevance

●● Moderate

The wildcard credential-inspection bypass is security-sensitive, but no closely matching accepted
precedent was found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1538316 requires permission expansions to be least-privilege and explicitly
authorized. The added example grants uninspected credential access to all Google API hosts, while
the established profile leaves inspection enabled for its Google endpoint and documents
authorization only for the narrower Anthropic exception.

examples/link-check/profiles/fullsend-vertex-ai.yaml[15-20]
profiles/fullsend-vertex-ai.yaml[12-27]
Skill: code-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The example profile sets `allow_uninspected_credentials: true` for the wildcard `*.googleapis.com` endpoint without explicit authorization or a demonstrated least-privilege need.

## Issue Context
The primary repository profile applies this security-sensitive exception only to `api.anthropic.com` and documents its approval through issue #6695 and ADR 0092. Keep the example aligned with that narrower policy unless a linked issue or ADR explicitly authorizes the Google API bypass.

## Fix Focus Areas
- examples/link-check/profiles/fullsend-vertex-ai.yaml[15-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Truncation exceeds comment limit ✓ Resolved 🐞 Bug ≡ Correctness
Description
The post-script retains 16,384 characters and then appends a truncation suffix, producing a comment
longer than the declared 16,384-character maximum. This defeats the cap that the schema, prompt, and
constant all specify.
Code

examples/link-check/scripts/post-link-check.sh[R51-53]

+if (( ${#comment} > MAX_COMMENT_CHARS )); then
+  comment="${comment:0:${MAX_COMMENT_CHARS}}"$'\n\n_(truncated)_'
+fi
Relevance

●●● Strong

The suffix is appended after taking the full limit, deterministically exceeding the schema’s maximum
length.

PR-#10

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The schema and prompt cap comment at 16,384 characters. The script slices the comment to that full
length before appending two newlines and _(truncated)_, while its test only looks for the marker.

examples/link-check/schemas/link-check-result.schema.json[7-10]
examples/link-check/agents/link-check.md[67-72]
examples/link-check/scripts/post-link-check.sh[24-25]
examples/link-check/scripts/post-link-check.sh[51-53]
scripts/example-link-check-test.sh[122-133]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When truncating an oversized comment, reserve enough characters for the newline and truncation marker so the final rendered comment remains within `MAX_COMMENT_CHARS`.

## Issue Context
The current test checks only that the marker exists and does not assert the final output length.

## Fix Focus Areas
- examples/link-check/scripts/post-link-check.sh[24-25]
- examples/link-check/scripts/post-link-check.sh[51-53]
- scripts/example-link-check-test.sh[122-133]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Result schema is unenforced ✓ Resolved 🐞 Bug ☼ Reliability
Description
The harness adds a result schema but no validation_loop referencing it, unlike every existing
schema-backed fleet harness. Invalid output can therefore reach the post-script without the declared
schema validation or retry behavior.
Code

examples/link-check/harness/link-check.yaml[R27-29]

+model: opus
+effort: high
+post_script: scripts/post-link-check.sh
Relevance

●●● Strong

The schema is otherwise unused, so invalid model output bypasses the declared validation and retry
mechanism.

PR-#1050

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new harness configures only the post-script around this section, while the schema is otherwise
unreferenced. Existing review harness configuration explicitly connects its schema through
validation_loop, and the shared validator documents that it is invoked by that mechanism.

examples/link-check/harness/link-check.yaml[27-30]
examples/link-check/schemas/link-check-result.schema.json[1-33]
harness/review.yaml[43-49]
scripts/validate-output-schema.sh[1-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Configure the example harness to validate agent output against its added result schema before running the post-script.

## Issue Context
Existing harnesses use `scripts/validate-output-schema.sh` through `validation_loop`; that script requires the configured schema path and validates the iteration output.

## Fix Focus Areas
- examples/link-check/harness/link-check.yaml[27-30]
- examples/link-check/schemas/link-check-result.schema.json[1-33]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 57 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review
Review mode: ⚖️ Balanced

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread examples/link-check/profiles/fullsend-vertex-ai.yaml
Comment thread scripts/example-link-check-test.sh
Comment thread examples/link-check/agents/link-check.md Outdated
Comment thread examples/link-check/agents/link-check.md Outdated
Comment thread examples/link-check/harness/link-check.yaml
Comment thread examples/link-check/scripts/post-link-check.sh
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (validation failed after 2 iteration(s)) · Started 4:42 PM UTC · Completed 5:24 PM UTC

Commit: a2b1f10 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high

@waynesun09

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Ended 5:31 PM UTC

Commit: 1f1944f · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 3, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (validation failed after 2 iteration(s)) · Started 5:32 PM UTC · Completed 6:14 PM UTC

Commit: 1f1944f · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.35

Comment thread examples/README.md Outdated
Comment thread examples/README.md Outdated
Comment thread examples/README.md Outdated
@rh-hemartin

Copy link
Copy Markdown
Member

At least publicise the skill in our docs, briefly mention it, we don't need a 200 words paragraph to say "we have a skill to do this we are about to do in this document, use it".

@waynesun09

Copy link
Copy Markdown
Member Author

Also added the authoring-skill pointer you asked for, in 49f5ee7 — one sentence at the end of docs/README.md, where the existing "building your own agents" line already sits:

To build one, run fullsend agent new and then follow the authoring-custom-agents skill to complete the generated prompt; examples/link-check/ is a finished one.

Head is now 49f5ee7.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 3:06 PM UTC · Ended 3:12 PM UTC

Commit: 49f5ee7 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 3:14 PM UTC · Ended 3:47 PM UTC

Commit: 54ca2a6 · View workflow run →

waynesun09 added a commit to fullsend-ai/fullsend that referenced this pull request Sep 4, 2026
The generated prompt says the summary is one line and the generated
post-script refuses one that is not, but the generated schema only
constrained type and length. So a multi-line summary passed the
validation loop, no retry was triggered, and the run died in the
post-script with nothing posted — the three files that are supposed to
describe one contract described two.

Found reviewing the reference agent in fullsend-ai/agents#1167, which is
generated from this template.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 3:49 PM UTC · Ended 3:59 PM UTC

Commit: eb5452a · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 4:01 PM UTC · Ended 4:10 PM UTC

Commit: 1592030 · View workflow run →

`fullsend agent new` (fullsend-ai/fullsend#6966) generates a valid agent
skeleton; these are the two things it hands off to.

examples/link-check/ is a complete agent generated by that command and
then finished — the tree the generator produces, with the prompt filled
in. It lives under examples/ rather than in the fleet directories: those
are consumed by URL via `agent add`, and anything placed there reads as
a first-class agent. It is deliberately not registered in config.yaml.

Being an example is not a reason for it to be unchecked, since it exists
to be copied:

- skillsaw now runs content rules over examples/**/agents/*.md. It did
  not before — verified by planting a FILL IN marker and a TODO, which
  passed `make lint --strict` unnoticed; with the content-paths entry
  the same plant fails the build.
- The post-script gets a test wired into `make test`. It consumes
  untrusted model output, so it is held to the same standard as a fleet
  one: the 16 cases cover the field allowlist, non-string coercion,
  length caps, and ISSUE_URL validation including a foreign host and a
  path-traversal attempt.

skills/authoring-custom-agents/ is the procedure for completing a
generated skeleton: replace every marker, keep the output contract, the
schema and the post-script naming the same fields, keep tools: matching
the body, and leave all mutation to the post-script. It is named apart
from the existing agent-scaffolding skill, which is a diagnostic lens
for evaluating agent infrastructure rather than an authoring procedure.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
…he cap

Three fixes to the reference agent, from review.

The prompt checked every link in each changed file, so a pre-existing
broken link in a touched file surfaced as a finding against whoever
touched it. It now extracts links only from lines the pull request adds
(`git diff -U0 --diff-filter=AMR base...HEAD -- '*.md'`), and says why:
blaming an author for a link they did not write is the fastest way to
get an agent's comments ignored. `--diff-filter=AMR` also drops files
the pull request deletes, which previously survived the filter and then
failed to open at head. `tools:` gains git to match the body.

The post-script cut the comment at the 16384-character cap and then
appended the truncation marker, overshooting the limit the result schema
declares. It now reserves the marker's length: a 17,000-character
comment prints at exactly 16384. The fix is in the shared generator
template, so it reaches every future generated agent, and the shell test
now measures the emitted body rather than only looking for the marker.

The example is regenerated with --validation-loop. The CLI default is
opt-in, but every schema-backed fleet harness here uses one and the
runner has python3 with jsonschema, so the example matches fleet
convention — and it exercises the generated preflight_check, which
reports a missing dependency before sandbox creation instead of after a
full inference run.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
…ng skill

The examples README described itself in fullsend jargon. It now says
plainly what happened: the generator wrote every file except the prompt,
and what was added by hand is the body of agents/<name>.md plus the
choice of trigger and scope. "Fleet agents" becomes "the agents in this
repository's harness/ directory", and the sentence explaining what an
examples directory is has gone — a reader who has opened it does not
need telling.

docs/README.md gains one sentence where someone about to build an agent
would look: run `fullsend agent new`, then follow the
authoring-custom-agents skill to complete the prompt, with the
link-check example as a finished one.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
The three review comments on the README were one defect, and fixing only
the lines pointed at left the rest. "Fleet" survived twice more — "fleet
harness", "a fleet one" — so both are now "the agents in this
repository's harness/ directory" and "the ones in scripts/". "The
generator pins the current sandbox image" is now what that means: it
records the exact container image those agents run on. "Vendor",
"scaffold" and "inference run" are gone the same way.

The authoring skill introduced agent definition, result schema and
post-script by name and then relied on them; it now says what each one
is and, for the post-script, that it is the only thing that touches the
issue or pull request — which is the point of the separation the skill
goes on to enforce.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
The generator template had the post-script looking for its input in the
wrong directory (fullsend-ai/fullsend#6972), so the example carried the
same defect and this repository's test confirmed it: run_post built
<tmp>/output/agent-result.json and ran from there, which is not the
layout fullsend provides. Seventeen assertions passed against a script
that could not have worked.

The test now builds iteration-<N>/output/ and runs from the run
directory, as internal/cli/run.go does, and adds the two cases the old
shape could not express: that the highest-numbered iteration wins, and
that FULLSEND_VALIDATED_ITERATION_DIR overrides it.

The example is regenerated from the fixed template, which also brings
the locale pin, the JSON-object shape check in place of `jq -e .`, the
single-line summary check, and the work_item guard that keeps the
trigger off GitHub Discussions. Three more reject cases cover shapes the
old `jq -e .` gate got wrong: a bare null, a bare false, and a
top-level array.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
A second review round, three reviewers, found that the example agent was
documented rather than possible.

Step 1 called `gh pr view --json`, which `gh` implements over GraphQL,
and step 2 called `git diff` — but the sandbox profile the generator
copies permits only the `gh` and `node` binaries, and its endpoint list
has no GraphQL entry. Both steps would have been refused at the egress
layer before the agent did any work.

The steps now use `gh api .../pulls/{n}/files`, which is REST, needs no
`git`, and returns the per-file patch hunks the agent actually wants.
`git` comes back out of `tools:`, and `jq` earns its place there for the
first time. The added-line walk is spelled out — a hunk header restarts
the counter — because a model asked for head line numbers without being
told how to derive them will invent them.

Reference-style links were being resolved against the diff rather than
the document, so a link whose definition sat on an unchanged line was
never checked; unused definitions are now skipped instead of reported,
since one renders nothing. Query strings and percent-encoding are
stripped before the existence check.

The result schema now carries a `pattern` forbidding newlines in
`summary`, which is a generator change: the prompt and the post-script
both required a single line, and only the schema did not — so a
multi-line summary passed validation and died in the post-script with
nothing posted.

The README claimed the trigger was "pr-opened" when the harness fires on
opened, synchronized and marked_ready and skips forks, and stated a
`fullsend lock` criterion without saying that command needs a
config.yaml the example deliberately does not have. The skill gave two
different invocations for the same command.

Four tests added for behaviour that had none: iteration-10 beating
iteration-9, a validated iteration directory with no result, a posting
`status: error`, and a missing GH_TOKEN.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
A fourth reviewer went over this and found the example asserting things
that are not true, including one I had claimed as verified.

The FILL-IN gate does not exist. I wrote that `skillsaw --strict` fails
on an unfilled `<!-- FILL IN -->` marker and showed before/after output
to prove it — but that test appended a `TODO` line as well, and the TODO
is what failed the build. Isolating them shows the marker alone passes
with zero warnings. `FILL IN` is precisely what `fullsend agent new`
emits, so the one gate this PR added `content-paths` for did not fire on
the one marker that matters. `example-link-check-test.sh` now greps for
it, scoped to agent definitions so the README can still name it in
prose, and both directions are verified.

Step 1 could not run. `gh api "repos/{owner}/{repo}/pulls/{number}/files"`
looks like it interpolates, but `{owner}` and `{repo}` are gh's own
placeholders for the current checkout's remote and there is no
`{number}` placeholder at all — a literal one goes through unsubstituted
and returns 404. The step now parses ISSUE_URL and interpolates, and
says why, since the failure looks like a permissions problem.

The rationale was wrong even where the conclusion was right. A profile's
`binaries:` list restricts which programs may reach a network endpoint;
it does not stop `git` from running. `git diff` against the base fails
here because the checkout is shallow and not at the pull request's head
— that is the real reason and the one a reader should carry away.

Also: the byte-identity claim now names the files it is true of, since
the post-script and schema carry fixes queued for the generator; the
`fullsend lock` caveat is gone because lock resolves a harness by path
and never needed a config.yaml; optional link titles and angle-bracket
destinations are handled; candidates inside code spans are skipped; a
null `patch` and the 3,000-file cap report `error` rather than a false
`ok`; and `Grep` leaves `tools:`, which nothing used.

The skill gains the enforcement half of its own rule 6: `readonly_repo:
true` is a harness field, and a prompt asking an agent not to mutate is
a request where that field is a guarantee.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
Rebased onto origin/main, which brings fullsend-ai/fullsend#6975 into
the generator's embedded scaffold: the Vertex profile now allows
`**/claude.exe` and `**/pi` alongside `**/claude`. On the v0.40.0 sandbox
image the Claude binary is `claude.exe`, so before that fix it matched no
profile's binaries list, no egress policy applied to it, and every
request it made was refused — which is what a local `--runtime claude`
run of this example hit.

The example's copied profile carries the fix now, and examples/README.md
gains the step that was missing for anyone trying to run one: these are
deliberately absent from this repository's config.yaml, so `fullsend
run` cannot resolve them until you register a copy. The exact error and
the `fullsend agent add` command that avoids it are both in the README —
found by hitting it.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@waynesun09
waynesun09 force-pushed the agent-6966-agent-templates branch from 1592030 to ca26a6c Compare September 4, 2026 16:09
waynesun09 added a commit to fullsend-ai/fullsend that referenced this pull request Sep 4, 2026
The generated prompt says the summary is one line and the generated
post-script refuses one that is not, but the generated schema only
constrained type and length. So a multi-line summary passed the
validation loop, no retry was triggered, and the run died in the
post-script with nothing posted — the three files that are supposed to
describe one contract described two.

Found reviewing the reference agent in fullsend-ai/agents#1167, which is
generated from this template.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 4:13 PM UTC · Ended 4:38 PM UTC

Commit: ca26a6c · View workflow run →

Running the example against a real pull request showed the agent
reasoning about whether a path "exists at the pull request head" rather
than checking the tree in front of it — because the prompt told it the
repository was checked out at that head. It is not: the review stage
checks out the default branch, shallow, so a file the pull request adds
is absent and a file it deletes is still present.

The Inputs section now says that, and step 5 says what to do about it:
a path the pull request itself adds resolves once merged even though it
is not on disk, and anything else is checked against the checkout. The
previous wording invited exactly the inference the run produced.

Verified by running it: exit 0, schema validation passed, post-script
printed rather than posted.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 4, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (validation failed after 2 iteration(s)) · Started 4:40 PM UTC · Completed 5:22 PM UTC

Commit: 8f9272f · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants